From fd2033e5d5e6db907aa054f3f57aa328d5fae7f9 Mon Sep 17 00:00:00 2001 From: John Luo Date: Thu, 12 Sep 2019 22:34:52 -0700 Subject: [PATCH 1/9] Support netcoreapp3.1 TFM (dotnet/extensions#2336) * Support netcoreapp3.1 TFM * Unpin SDK for source build * Update to preview1 branding \n\nCommit migrated from https://github.com/dotnet/extensions/commit/32cc8162ff38356b293611138d361f757a62e025 --- .../Microsoft.Extensions.Configuration.KeyPerFile.csproj | 6 +++--- ...osoft.Extensions.Configuration.KeyPerFile.netcoreapp.cs} | 0 .../Microsoft.Extensions.Configuration.KeyPerFile.csproj | 4 ++-- ...crosoft.Extensions.Configuration.KeyPerFile.Tests.csproj | 2 +- .../ref/Microsoft.Extensions.FileProviders.Embedded.csproj | 6 +++--- ...crosoft.Extensions.FileProviders.Embedded.netcoreapp.cs} | 0 .../src/Microsoft.Extensions.FileProviders.Embedded.csproj | 6 +++--- ...oft.Extensions.FileProviders.Embedded.multitarget.nuspec | 2 +- ...oft.Extensions.FileProviders.Embedded.netcoreapp.nuspec} | 2 +- ...Microsoft.Extensions.FileProviders.Embedded.Tests.csproj | 2 +- ...nsions.FileProviders.Embedded.Manifest.Task.Tests.csproj | 2 +- ....Extensions.Diagnostics.HealthChecks.Abstractions.csproj | 6 +++--- ...ons.Diagnostics.HealthChecks.Abstractions.netcoreapp.cs} | 0 ....Extensions.Diagnostics.HealthChecks.Abstractions.csproj | 4 ++-- .../Microsoft.Extensions.Diagnostics.HealthChecks.csproj | 6 +++--- ...osoft.Extensions.Diagnostics.HealthChecks.netcoreapp.cs} | 0 .../Microsoft.Extensions.Diagnostics.HealthChecks.csproj | 4 ++-- ...crosoft.Extensions.Diagnostics.HealthChecks.Tests.csproj | 2 +- .../Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj | 6 +++--- ...p.netcoreapp3.0.cs => Microsoft.JSInterop.netcoreapp.cs} | 0 .../Microsoft.JSInterop/src/Microsoft.JSInterop.csproj | 4 ++-- .../test/Microsoft.JSInterop.Tests.csproj | 2 +- .../Microsoft.Extensions.Localization.Abstractions.csproj | 6 +++--- ...soft.Extensions.Localization.Abstractions.netcoreapp.cs} | 0 .../Microsoft.Extensions.Localization.Abstractions.csproj | 4 ++-- .../ref/Microsoft.Extensions.Localization.csproj | 6 +++--- ...0.cs => Microsoft.Extensions.Localization.netcoreapp.cs} | 0 .../src/Microsoft.Extensions.Localization.csproj | 4 ++-- .../test/Microsoft.Extensions.Localization.Tests.csproj | 2 +- .../test/Microsoft.Extensions.ObjectPool.Tests.csproj | 2 +- src/Shared/ActivatorUtilities/ActivatorUtilities.cs | 2 +- src/Shared/BenchmarkRunner/DefaultCoreConfig.cs | 6 +++++- src/Shared/test/Shared.Tests/DotNetMuxerTests.cs | 2 +- .../Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj | 2 +- .../BuildWebHostInvalidSignature.csproj | 2 +- .../BuildWebHostPatternTestSite.csproj | 2 +- .../CreateHostBuilderInvalidSignature.csproj | 2 +- .../CreateHostBuilderPatternTestSite.csproj | 2 +- .../CreateWebHostBuilderInvalidSignature.csproj | 2 +- .../CreateWebHostBuilderPatternTestSite.csproj | 2 +- .../test/testassets/MockHostTypes/MockHostTypes.csproj | 2 +- src/Testing/test/ConditionalFactTest.cs | 2 +- src/Testing/test/ConditionalTheoryTest.cs | 2 +- src/Testing/test/Microsoft.AspNetCore.Testing.Tests.csproj | 2 +- src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj | 6 +++--- ....0.cs => Microsoft.Extensions.WebEncoders.netcoreapp.cs} | 0 src/WebEncoders/src/Microsoft.Extensions.WebEncoders.csproj | 4 ++-- .../test/Microsoft.Extensions.WebEncoders.Tests.csproj | 2 +- 48 files changed, 69 insertions(+), 65 deletions(-) rename src/Configuration.KeyPerFile/ref/{Microsoft.Extensions.Configuration.KeyPerFile.netcoreapp3.0.cs => Microsoft.Extensions.Configuration.KeyPerFile.netcoreapp.cs} (100%) rename src/FileProviders/Embedded/ref/{Microsoft.Extensions.FileProviders.Embedded.netcoreapp3.0.cs => Microsoft.Extensions.FileProviders.Embedded.netcoreapp.cs} (100%) rename src/FileProviders/Embedded/src/{Microsoft.Extensions.FileProviders.Embedded.netcoreapp3.0.nuspec => Microsoft.Extensions.FileProviders.Embedded.netcoreapp.nuspec} (94%) rename src/HealthChecks/Abstractions/ref/{Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netcoreapp3.0.cs => Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netcoreapp.cs} (100%) rename src/HealthChecks/HealthChecks/ref/{Microsoft.Extensions.Diagnostics.HealthChecks.netcoreapp3.0.cs => Microsoft.Extensions.Diagnostics.HealthChecks.netcoreapp.cs} (100%) rename src/JSInterop/Microsoft.JSInterop/ref/{Microsoft.JSInterop.netcoreapp3.0.cs => Microsoft.JSInterop.netcoreapp.cs} (100%) rename src/Localization/Abstractions/ref/{Microsoft.Extensions.Localization.Abstractions.netcoreapp3.0.cs => Microsoft.Extensions.Localization.Abstractions.netcoreapp.cs} (100%) rename src/Localization/Localization/ref/{Microsoft.Extensions.Localization.netcoreapp3.0.cs => Microsoft.Extensions.Localization.netcoreapp.cs} (100%) rename src/WebEncoders/ref/{Microsoft.Extensions.WebEncoders.netcoreapp3.0.cs => Microsoft.Extensions.WebEncoders.netcoreapp.cs} (100%) diff --git a/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj b/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj index 4e074ab493..5500c4ddc8 100644 --- a/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj +++ b/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj @@ -1,15 +1,15 @@ - netstandard2.0;netcoreapp3.0 + netstandard2.0;netcoreapp3.1 - - + + diff --git a/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.netcoreapp3.0.cs b/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.netcoreapp.cs similarity index 100% rename from src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.netcoreapp3.0.cs rename to src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.netcoreapp.cs diff --git a/src/Configuration.KeyPerFile/src/Microsoft.Extensions.Configuration.KeyPerFile.csproj b/src/Configuration.KeyPerFile/src/Microsoft.Extensions.Configuration.KeyPerFile.csproj index 10f41fa9f4..7f9c5e7eb1 100644 --- a/src/Configuration.KeyPerFile/src/Microsoft.Extensions.Configuration.KeyPerFile.csproj +++ b/src/Configuration.KeyPerFile/src/Microsoft.Extensions.Configuration.KeyPerFile.csproj @@ -2,8 +2,8 @@ Configuration provider that uses files in a directory for Microsoft.Extensions.Configuration. - netstandard2.0;netcoreapp3.0 - netcoreapp3.0 + netstandard2.0;$(DefaultNetCoreTargetFramework) + $(DefaultNetCoreTargetFramework) true true diff --git a/src/Configuration.KeyPerFile/test/Microsoft.Extensions.Configuration.KeyPerFile.Tests.csproj b/src/Configuration.KeyPerFile/test/Microsoft.Extensions.Configuration.KeyPerFile.Tests.csproj index 95a73ae6cf..096cf2e2e0 100644 --- a/src/Configuration.KeyPerFile/test/Microsoft.Extensions.Configuration.KeyPerFile.Tests.csproj +++ b/src/Configuration.KeyPerFile/test/Microsoft.Extensions.Configuration.KeyPerFile.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 diff --git a/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj b/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj index e9407f9164..355c5b738e 100644 --- a/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj +++ b/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj @@ -1,14 +1,14 @@ - netstandard2.0;netcoreapp3.0 + netstandard2.0;netcoreapp3.1 - - + + diff --git a/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.netcoreapp3.0.cs b/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.netcoreapp.cs similarity index 100% rename from src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.netcoreapp3.0.cs rename to src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.netcoreapp.cs diff --git a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj index d36323e3b1..dc49b3fd75 100644 --- a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj +++ b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj @@ -3,10 +3,10 @@ Microsoft.Extensions.FileProviders File provider for files in embedded resources for Microsoft.Extensions.FileProviders. - netstandard2.0;netcoreapp3.0 + netstandard2.0;$(DefaultNetCoreTargetFramework) $(MSBuildProjectName).multitarget.nuspec - netcoreapp3.0 - $(MSBuildProjectName).netcoreapp3.0.nuspec + $(DefaultNetCoreTargetFramework) + $(MSBuildProjectName).netcoreapp.nuspec true true diff --git a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.multitarget.nuspec b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.multitarget.nuspec index 874c90c79d..59a0e89b7f 100644 --- a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.multitarget.nuspec +++ b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.multitarget.nuspec @@ -3,7 +3,7 @@ $CommonMetadataElements$ - + diff --git a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp3.0.nuspec b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp.nuspec similarity index 94% rename from src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp3.0.nuspec rename to src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp.nuspec index f98f0b4ad5..b0e9df4875 100644 --- a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp3.0.nuspec +++ b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp.nuspec @@ -3,7 +3,7 @@ $CommonMetadataElements$ - + diff --git a/src/FileProviders/Embedded/test/Microsoft.Extensions.FileProviders.Embedded.Tests.csproj b/src/FileProviders/Embedded/test/Microsoft.Extensions.FileProviders.Embedded.Tests.csproj index 8377747702..a199e43837 100644 --- a/src/FileProviders/Embedded/test/Microsoft.Extensions.FileProviders.Embedded.Tests.csproj +++ b/src/FileProviders/Embedded/test/Microsoft.Extensions.FileProviders.Embedded.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 diff --git a/src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Tests.csproj b/src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Tests.csproj index ed68958fe8..06afd574e8 100644 --- a/src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Tests.csproj +++ b/src/FileProviders/Manifest.MSBuildTask/test/Microsoft.Extensions.FileProviders.Embedded.Manifest.Task.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0 + $(DefaultNetCoreTargetFramework) diff --git a/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj b/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj index f7514489fa..e09ee43981 100644 --- a/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj +++ b/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj @@ -1,14 +1,14 @@ - netstandard2.0;netcoreapp3.0 + netstandard2.0;netcoreapp3.1 - - + + diff --git a/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netcoreapp3.0.cs b/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netcoreapp.cs similarity index 100% rename from src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netcoreapp3.0.cs rename to src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netcoreapp.cs diff --git a/src/HealthChecks/Abstractions/src/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj b/src/HealthChecks/Abstractions/src/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj index f41b257c63..aeb85d3e76 100644 --- a/src/HealthChecks/Abstractions/src/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj +++ b/src/HealthChecks/Abstractions/src/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj @@ -7,8 +7,8 @@ Commonly Used Types Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck Microsoft.Extensions.Diagnostics.HealthChecks - netstandard2.0;netcoreapp3.0 - netcoreapp3.0 + netstandard2.0;$(DefaultNetCoreTargetFramework) + $(DefaultNetCoreTargetFramework) $(NoWarn);CS1591 true diagnostics;healthchecks diff --git a/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj b/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj index 2286087bc7..a2080b28d3 100644 --- a/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj +++ b/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netcoreapp3.0 + netstandard2.0;netcoreapp3.1 @@ -9,8 +9,8 @@ - - + + diff --git a/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.netcoreapp3.0.cs b/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.netcoreapp.cs similarity index 100% rename from src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.netcoreapp3.0.cs rename to src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.netcoreapp.cs diff --git a/src/HealthChecks/HealthChecks/src/Microsoft.Extensions.Diagnostics.HealthChecks.csproj b/src/HealthChecks/HealthChecks/src/Microsoft.Extensions.Diagnostics.HealthChecks.csproj index 4005685011..35c789a691 100644 --- a/src/HealthChecks/HealthChecks/src/Microsoft.Extensions.Diagnostics.HealthChecks.csproj +++ b/src/HealthChecks/HealthChecks/src/Microsoft.Extensions.Diagnostics.HealthChecks.csproj @@ -6,8 +6,8 @@ Commonly Used Types: Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckService Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder - netstandard2.0;netcoreapp3.0 - netcoreapp3.0 + netstandard2.0;$(DefaultNetCoreTargetFramework) + $(DefaultNetCoreTargetFramework) $(NoWarn);CS1591 true diagnostics;healthchecks diff --git a/src/HealthChecks/HealthChecks/test/Microsoft.Extensions.Diagnostics.HealthChecks.Tests.csproj b/src/HealthChecks/HealthChecks/test/Microsoft.Extensions.Diagnostics.HealthChecks.Tests.csproj index 21763e5165..b6fa1537da 100644 --- a/src/HealthChecks/HealthChecks/test/Microsoft.Extensions.Diagnostics.HealthChecks.Tests.csproj +++ b/src/HealthChecks/HealthChecks/test/Microsoft.Extensions.Diagnostics.HealthChecks.Tests.csproj @@ -3,7 +3,7 @@ - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 Microsoft.Extensions.Diagnostics.HealthChecks diff --git a/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj b/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj index 61980aa920..3c07525347 100644 --- a/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj +++ b/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj @@ -1,14 +1,14 @@ - netstandard2.0;netcoreapp3.0 + netstandard2.0;netcoreapp3.1 - - + + diff --git a/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.netcoreapp3.0.cs b/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.netcoreapp.cs similarity index 100% rename from src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.netcoreapp3.0.cs rename to src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.netcoreapp.cs diff --git a/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.csproj b/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.csproj index 044c843b28..a45484e0d3 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.csproj +++ b/src/JSInterop/Microsoft.JSInterop/src/Microsoft.JSInterop.csproj @@ -1,8 +1,8 @@  - netstandard2.0;netcoreapp3.0 - netcoreapp3.0 + netstandard2.0;$(DefaultNetCoreTargetFramework) + $(DefaultNetCoreTargetFramework) Abstractions and features for interop between .NET and JavaScript code. javascript;interop true diff --git a/src/JSInterop/Microsoft.JSInterop/test/Microsoft.JSInterop.Tests.csproj b/src/JSInterop/Microsoft.JSInterop/test/Microsoft.JSInterop.Tests.csproj index bff8fb3f99..ba3a91a94e 100644 --- a/src/JSInterop/Microsoft.JSInterop/test/Microsoft.JSInterop.Tests.csproj +++ b/src/JSInterop/Microsoft.JSInterop/test/Microsoft.JSInterop.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 diff --git a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj index 6404d5ae8e..c45066d3cb 100644 --- a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj +++ b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj @@ -1,14 +1,14 @@ - netstandard2.0;netcoreapp3.0 + netstandard2.0;netcoreapp3.1 - - + + diff --git a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netcoreapp3.0.cs b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netcoreapp.cs similarity index 100% rename from src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netcoreapp3.0.cs rename to src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.netcoreapp.cs diff --git a/src/Localization/Abstractions/src/Microsoft.Extensions.Localization.Abstractions.csproj b/src/Localization/Abstractions/src/Microsoft.Extensions.Localization.Abstractions.csproj index 09b8bf65b7..4b88160401 100644 --- a/src/Localization/Abstractions/src/Microsoft.Extensions.Localization.Abstractions.csproj +++ b/src/Localization/Abstractions/src/Microsoft.Extensions.Localization.Abstractions.csproj @@ -6,8 +6,8 @@ Commonly used types: Microsoft.Extensions.Localization.IStringLocalizer Microsoft.Extensions.Localization.IStringLocalizer<T> - netstandard2.0;netcoreapp3.0 - netcoreapp3.0 + netstandard2.0;$(DefaultNetCoreTargetFramework) + $(DefaultNetCoreTargetFramework) $(NoWarn);CS1591 true localization diff --git a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj index 735277e754..b6df43f5db 100644 --- a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj +++ b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netcoreapp3.0 + netstandard2.0;netcoreapp3.1 @@ -10,8 +10,8 @@ - - + + diff --git a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netcoreapp3.0.cs b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.netcoreapp.cs similarity index 100% rename from src/Localization/Localization/ref/Microsoft.Extensions.Localization.netcoreapp3.0.cs rename to src/Localization/Localization/ref/Microsoft.Extensions.Localization.netcoreapp.cs diff --git a/src/Localization/Localization/src/Microsoft.Extensions.Localization.csproj b/src/Localization/Localization/src/Microsoft.Extensions.Localization.csproj index 86ebaf1970..b6b059ce82 100644 --- a/src/Localization/Localization/src/Microsoft.Extensions.Localization.csproj +++ b/src/Localization/Localization/src/Microsoft.Extensions.Localization.csproj @@ -3,8 +3,8 @@ Microsoft .NET Extensions Application localization services and default implementation based on ResourceManager to load localized assembly resources. - netstandard2.0;netcoreapp3.0 - netcoreapp3.0 + netstandard2.0;$(DefaultNetCoreTargetFramework) + $(DefaultNetCoreTargetFramework) $(NoWarn);CS1591 true localization diff --git a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests.csproj b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests.csproj index 17254e2110..70e7a6de1a 100644 --- a/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests.csproj +++ b/src/Localization/Localization/test/Microsoft.Extensions.Localization.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 diff --git a/src/ObjectPool/test/Microsoft.Extensions.ObjectPool.Tests.csproj b/src/ObjectPool/test/Microsoft.Extensions.ObjectPool.Tests.csproj index 1f2ad67664..cc308fa8a0 100644 --- a/src/ObjectPool/test/Microsoft.Extensions.ObjectPool.Tests.csproj +++ b/src/ObjectPool/test/Microsoft.Extensions.ObjectPool.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 diff --git a/src/Shared/ActivatorUtilities/ActivatorUtilities.cs b/src/Shared/ActivatorUtilities/ActivatorUtilities.cs index 3fd2b557ff..4d05ebf589 100644 --- a/src/Shared/ActivatorUtilities/ActivatorUtilities.cs +++ b/src/Shared/ActivatorUtilities/ActivatorUtilities.cs @@ -402,7 +402,7 @@ namespace Microsoft.Extensions.Internal } } -#if NETCOREAPP3_0 +#if NETCOREAPP return _constructor.Invoke(BindingFlags.DoNotWrapExceptions, binder: null, parameters: _parameterValues, culture: null); #else try diff --git a/src/Shared/BenchmarkRunner/DefaultCoreConfig.cs b/src/Shared/BenchmarkRunner/DefaultCoreConfig.cs index a61833ab26..8329635017 100644 --- a/src/Shared/BenchmarkRunner/DefaultCoreConfig.cs +++ b/src/Shared/BenchmarkRunner/DefaultCoreConfig.cs @@ -30,8 +30,12 @@ namespace BenchmarkDotNet.Attributes Add(Job.Core #if NETCOREAPP2_1 .With(CsProjCoreToolchain.From(NetCoreAppSettings.NetCoreApp21)) -#else +#elif NETCOREAPP3_0 .With(CsProjCoreToolchain.From(new NetCoreAppSettings("netcoreapp3.0", null, ".NET Core 3.0"))) +#elif NETCOREAPP3_1 + .With(CsProjCoreToolchain.From(new NetCoreAppSettings("netcoreapp3.1", null, ".NET Core 3.1"))) +#else +#error Target frameworks need to be updated. #endif .With(new GcMode { Server = true }) .With(RunStrategy.Throughput)); diff --git a/src/Shared/test/Shared.Tests/DotNetMuxerTests.cs b/src/Shared/test/Shared.Tests/DotNetMuxerTests.cs index 2f412e292e..8840d87bb8 100644 --- a/src/Shared/test/Shared.Tests/DotNetMuxerTests.cs +++ b/src/Shared/test/Shared.Tests/DotNetMuxerTests.cs @@ -1,7 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -#if NETCOREAPP3_0 +#if NETCOREAPP using System.IO; using System.Runtime.InteropServices; using Xunit; diff --git a/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj b/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj index daf7eef7ea..5d7cd465c1 100644 --- a/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj +++ b/src/Shared/test/Shared.Tests/Microsoft.AspNetCore.Shared.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 true diff --git a/src/Shared/test/testassets/BuildWebHostInvalidSignature/BuildWebHostInvalidSignature.csproj b/src/Shared/test/testassets/BuildWebHostInvalidSignature/BuildWebHostInvalidSignature.csproj index 6368289f65..05ca293b6e 100644 --- a/src/Shared/test/testassets/BuildWebHostInvalidSignature/BuildWebHostInvalidSignature.csproj +++ b/src/Shared/test/testassets/BuildWebHostInvalidSignature/BuildWebHostInvalidSignature.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 Exe diff --git a/src/Shared/test/testassets/BuildWebHostPatternTestSite/BuildWebHostPatternTestSite.csproj b/src/Shared/test/testassets/BuildWebHostPatternTestSite/BuildWebHostPatternTestSite.csproj index 6368289f65..05ca293b6e 100644 --- a/src/Shared/test/testassets/BuildWebHostPatternTestSite/BuildWebHostPatternTestSite.csproj +++ b/src/Shared/test/testassets/BuildWebHostPatternTestSite/BuildWebHostPatternTestSite.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 Exe diff --git a/src/Shared/test/testassets/CreateHostBuilderInvalidSignature/CreateHostBuilderInvalidSignature.csproj b/src/Shared/test/testassets/CreateHostBuilderInvalidSignature/CreateHostBuilderInvalidSignature.csproj index 6368289f65..05ca293b6e 100644 --- a/src/Shared/test/testassets/CreateHostBuilderInvalidSignature/CreateHostBuilderInvalidSignature.csproj +++ b/src/Shared/test/testassets/CreateHostBuilderInvalidSignature/CreateHostBuilderInvalidSignature.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 Exe diff --git a/src/Shared/test/testassets/CreateHostBuilderPatternTestSite/CreateHostBuilderPatternTestSite.csproj b/src/Shared/test/testassets/CreateHostBuilderPatternTestSite/CreateHostBuilderPatternTestSite.csproj index 6368289f65..05ca293b6e 100644 --- a/src/Shared/test/testassets/CreateHostBuilderPatternTestSite/CreateHostBuilderPatternTestSite.csproj +++ b/src/Shared/test/testassets/CreateHostBuilderPatternTestSite/CreateHostBuilderPatternTestSite.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 Exe diff --git a/src/Shared/test/testassets/CreateWebHostBuilderInvalidSignature/CreateWebHostBuilderInvalidSignature.csproj b/src/Shared/test/testassets/CreateWebHostBuilderInvalidSignature/CreateWebHostBuilderInvalidSignature.csproj index 6368289f65..05ca293b6e 100644 --- a/src/Shared/test/testassets/CreateWebHostBuilderInvalidSignature/CreateWebHostBuilderInvalidSignature.csproj +++ b/src/Shared/test/testassets/CreateWebHostBuilderInvalidSignature/CreateWebHostBuilderInvalidSignature.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 Exe diff --git a/src/Shared/test/testassets/CreateWebHostBuilderPatternTestSite/CreateWebHostBuilderPatternTestSite.csproj b/src/Shared/test/testassets/CreateWebHostBuilderPatternTestSite/CreateWebHostBuilderPatternTestSite.csproj index 6368289f65..05ca293b6e 100644 --- a/src/Shared/test/testassets/CreateWebHostBuilderPatternTestSite/CreateWebHostBuilderPatternTestSite.csproj +++ b/src/Shared/test/testassets/CreateWebHostBuilderPatternTestSite/CreateWebHostBuilderPatternTestSite.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 Exe diff --git a/src/Shared/test/testassets/MockHostTypes/MockHostTypes.csproj b/src/Shared/test/testassets/MockHostTypes/MockHostTypes.csproj index 3272f8d93a..57b6e1ae58 100644 --- a/src/Shared/test/testassets/MockHostTypes/MockHostTypes.csproj +++ b/src/Shared/test/testassets/MockHostTypes/MockHostTypes.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 diff --git a/src/Testing/test/ConditionalFactTest.cs b/src/Testing/test/ConditionalFactTest.cs index 0f1c6ada46..fefe6c5a42 100644 --- a/src/Testing/test/ConditionalFactTest.cs +++ b/src/Testing/test/ConditionalFactTest.cs @@ -29,7 +29,7 @@ namespace Microsoft.AspNetCore.Testing Assert.True(false, "This test should always be skipped."); } -#if NETCOREAPP3_0 +#if NETCOREAPP [ConditionalFact] [FrameworkSkipCondition(RuntimeFrameworks.CLR)] public void ThisTestMustRunOnCoreCLR() diff --git a/src/Testing/test/ConditionalTheoryTest.cs b/src/Testing/test/ConditionalTheoryTest.cs index 12deaba4f9..e88a3334f2 100644 --- a/src/Testing/test/ConditionalTheoryTest.cs +++ b/src/Testing/test/ConditionalTheoryTest.cs @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Testing Assert.True(true); } -#if NETCOREAPP3_0 +#if NETCOREAPP [ConditionalTheory] [FrameworkSkipCondition(RuntimeFrameworks.CLR)] [MemberData(nameof(GetInts))] diff --git a/src/Testing/test/Microsoft.AspNetCore.Testing.Tests.csproj b/src/Testing/test/Microsoft.AspNetCore.Testing.Tests.csproj index e9d0dca4ae..5a7366503d 100644 --- a/src/Testing/test/Microsoft.AspNetCore.Testing.Tests.csproj +++ b/src/Testing/test/Microsoft.AspNetCore.Testing.Tests.csproj @@ -1,7 +1,7 @@  - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 $(NoWarn);xUnit1004 diff --git a/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj b/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj index 628691a220..283cb96e98 100644 --- a/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj +++ b/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netcoreapp3.0 + netstandard2.0;netcoreapp3.1 @@ -9,8 +9,8 @@ - - + + diff --git a/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.netcoreapp3.0.cs b/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.netcoreapp.cs similarity index 100% rename from src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.netcoreapp3.0.cs rename to src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.netcoreapp.cs diff --git a/src/WebEncoders/src/Microsoft.Extensions.WebEncoders.csproj b/src/WebEncoders/src/Microsoft.Extensions.WebEncoders.csproj index 2ed725eac7..364f4d3d86 100644 --- a/src/WebEncoders/src/Microsoft.Extensions.WebEncoders.csproj +++ b/src/WebEncoders/src/Microsoft.Extensions.WebEncoders.csproj @@ -2,8 +2,8 @@ Contains registration and configuration APIs to add the core framework encoders to a dependency injection container. - netstandard2.0;netcoreapp3.0 - netcoreapp3.0 + netstandard2.0;$(DefaultNetCoreTargetFramework) + $(DefaultNetCoreTargetFramework) $(NoWarn);CS1591 true aspnetcore diff --git a/src/WebEncoders/test/Microsoft.Extensions.WebEncoders.Tests.csproj b/src/WebEncoders/test/Microsoft.Extensions.WebEncoders.Tests.csproj index 68ad589e3f..0f93bf3fc6 100755 --- a/src/WebEncoders/test/Microsoft.Extensions.WebEncoders.Tests.csproj +++ b/src/WebEncoders/test/Microsoft.Extensions.WebEncoders.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0;net472 + $(DefaultNetCoreTargetFramework);net472 From 68f3765e6d677bd30383f97799133167045a9f22 Mon Sep 17 00:00:00 2001 From: John Luo Date: Mon, 16 Sep 2019 15:17:32 -0700 Subject: [PATCH 2/9] Fix packing on *nix systems (dotnet/extensions#2344) - Without this fix, the nupkg will be missing files if packed on *nix systems\n\nCommit migrated from https://github.com/dotnet/extensions/commit/51e8af72d5bb14b970dde12caa089d7357631614 --- .../src/Microsoft.Extensions.FileProviders.Embedded.csproj | 4 +--- ...oft.Extensions.FileProviders.Embedded.multitarget.nuspec | 6 +++--- ...soft.Extensions.FileProviders.Embedded.netcoreapp.nuspec | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj index dc49b3fd75..3d5fe3cf54 100644 --- a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj +++ b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.csproj @@ -27,9 +27,7 @@ - - - + diff --git a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.multitarget.nuspec b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.multitarget.nuspec index 59a0e89b7f..a11c9c591e 100644 --- a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.multitarget.nuspec +++ b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.multitarget.nuspec @@ -13,9 +13,9 @@ - - - + + + diff --git a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp.nuspec b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp.nuspec index b0e9df4875..3033cff8c9 100644 --- a/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp.nuspec +++ b/src/FileProviders/Embedded/src/Microsoft.Extensions.FileProviders.Embedded.netcoreapp.nuspec @@ -10,9 +10,9 @@ - - - + + + From 6371d93d181b4d74d421b9ed4a18734d6e492960 Mon Sep 17 00:00:00 2001 From: John Luo Date: Tue, 17 Sep 2019 11:17:34 -0700 Subject: [PATCH 3/9] Update ref assembly generation to use DefaultNetCoreTargetFramework property (dotnet/extensions#2359) \n\nCommit migrated from https://github.com/dotnet/extensions/commit/1f41bdc38668fcf1998fd29325e8267e4e034893 --- .../ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj | 4 ++-- .../ref/Microsoft.Extensions.FileProviders.Embedded.csproj | 4 ++-- ...ft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj | 4 ++-- .../ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj | 4 ++-- .../Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj | 4 ++-- .../ref/Microsoft.Extensions.Localization.Abstractions.csproj | 4 ++-- .../Localization/ref/Microsoft.Extensions.Localization.csproj | 4 ++-- src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj b/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj index 5500c4ddc8..8dbe6d3ba1 100644 --- a/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj +++ b/src/Configuration.KeyPerFile/ref/Microsoft.Extensions.Configuration.KeyPerFile.csproj @@ -1,14 +1,14 @@ - netstandard2.0;netcoreapp3.1 + netstandard2.0;$(DefaultNetCoreTargetFramework) - + diff --git a/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj b/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj index 355c5b738e..89cba5ba57 100644 --- a/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj +++ b/src/FileProviders/Embedded/ref/Microsoft.Extensions.FileProviders.Embedded.csproj @@ -1,13 +1,13 @@ - netstandard2.0;netcoreapp3.1 + netstandard2.0;$(DefaultNetCoreTargetFramework) - + diff --git a/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj b/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj index e09ee43981..6b67a08686 100644 --- a/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj +++ b/src/HealthChecks/Abstractions/ref/Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.csproj @@ -1,13 +1,13 @@ - netstandard2.0;netcoreapp3.1 + netstandard2.0;$(DefaultNetCoreTargetFramework) - + diff --git a/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj b/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj index a2080b28d3..83dae521fb 100644 --- a/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj +++ b/src/HealthChecks/HealthChecks/ref/Microsoft.Extensions.Diagnostics.HealthChecks.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netcoreapp3.1 + netstandard2.0;$(DefaultNetCoreTargetFramework) @@ -9,7 +9,7 @@ - + diff --git a/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj b/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj index 3c07525347..ceb24636ab 100644 --- a/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj +++ b/src/JSInterop/Microsoft.JSInterop/ref/Microsoft.JSInterop.csproj @@ -1,13 +1,13 @@ - netstandard2.0;netcoreapp3.1 + netstandard2.0;$(DefaultNetCoreTargetFramework) - + diff --git a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj index c45066d3cb..af97cae594 100644 --- a/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj +++ b/src/Localization/Abstractions/ref/Microsoft.Extensions.Localization.Abstractions.csproj @@ -1,13 +1,13 @@ - netstandard2.0;netcoreapp3.1 + netstandard2.0;$(DefaultNetCoreTargetFramework) - + diff --git a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj index b6df43f5db..67e8f38f89 100644 --- a/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj +++ b/src/Localization/Localization/ref/Microsoft.Extensions.Localization.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netcoreapp3.1 + netstandard2.0;$(DefaultNetCoreTargetFramework) @@ -10,7 +10,7 @@ - + diff --git a/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj b/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj index 283cb96e98..5beee97dd6 100644 --- a/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj +++ b/src/WebEncoders/ref/Microsoft.Extensions.WebEncoders.csproj @@ -1,7 +1,7 @@ - netstandard2.0;netcoreapp3.1 + netstandard2.0;$(DefaultNetCoreTargetFramework) @@ -9,7 +9,7 @@ - + From ef2dc5024feb965dbd1205c0904ca2114872420c Mon Sep 17 00:00:00 2001 From: Pranav K Date: Thu, 19 Sep 2019 10:48:09 -0700 Subject: [PATCH 4/9] Add support for JSInvokable methods on generic types (dotnet/extensions#2342) * Add support for JSInvokable methods on generic types Prior to this change, DotNetDispatcher cached the MethodInfo on the generic type definition. Using this would have required MethodInfo.MakeGenericMethod before the method was invoked. We could separately cache the result of this to avoid the reflection cost per invocation. Alternatively we could cache static and non-static MethodInfo instances separately which is what this change attempts to do. The big difference in the outcome is that this requires instance (non-static) JSInvokable methods to be only unique named within the type hierarchy as opposed to across all static and instance JSInvokable methods in an assembly. Fixes https://github.com/aspnet/Extensions/issues/1360 Fixes https://github.com/aspnet/AspNetCore/issues/9061 \n\nCommit migrated from https://github.com/dotnet/extensions/commit/659b604fb2e595d48a931a7ed831f6c38f035382 --- .../src/Infrastructure/DotNetDispatcher.cs | 83 ++++++++++++------ .../Infrastructure/DotNetDispatcherTest.cs | 87 ++++++++++++++++++- 2 files changed, 142 insertions(+), 28 deletions(-) diff --git a/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/DotNetDispatcher.cs b/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/DotNetDispatcher.cs index 6a3a4f8d5f..8d37905980 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/DotNetDispatcher.cs +++ b/src/JSInterop/Microsoft.JSInterop/src/Infrastructure/DotNetDispatcher.cs @@ -24,6 +24,9 @@ namespace Microsoft.JSInterop.Infrastructure private static readonly ConcurrentDictionary> _cachedMethodsByAssembly = new ConcurrentDictionary>(); + private static readonly ConcurrentDictionary> _cachedMethodsByType + = new ConcurrentDictionary>(); + /// /// Receives a call from JS to .NET, locating and invoking the specified method. /// @@ -129,9 +132,12 @@ namespace Microsoft.JSInterop.Infrastructure var methodIdentifier = callInfo.MethodIdentifier; AssemblyKey assemblyKey; + MethodInfo methodInfo; + Type[] parameterTypes; if (objectReference is null) { assemblyKey = new AssemblyKey(assemblyName); + (methodInfo, parameterTypes) = GetCachedMethodInfo(assemblyKey, methodIdentifier); } else { @@ -147,11 +153,9 @@ namespace Microsoft.JSInterop.Infrastructure return default; } - assemblyKey = new AssemblyKey(objectReference.Value.GetType().Assembly); + (methodInfo, parameterTypes) = GetCachedMethodInfo(objectReference, methodIdentifier); } - var (methodInfo, parameterTypes) = GetCachedMethodInfo(assemblyKey, methodIdentifier); - var suppliedArgs = ParseArguments(jsRuntime, methodIdentifier, argsJson, parameterTypes); try @@ -301,7 +305,47 @@ namespace Microsoft.JSInterop.Infrastructure } else { - throw new ArgumentException($"The assembly '{assemblyKey.AssemblyName}' does not contain a public method with [{nameof(JSInvokableAttribute)}(\"{methodIdentifier}\")]."); + throw new ArgumentException($"The assembly '{assemblyKey.AssemblyName}' does not contain a public invokable method with [{nameof(JSInvokableAttribute)}(\"{methodIdentifier}\")]."); + } + } + + private static (MethodInfo methodInfo, Type[] parameterTypes) GetCachedMethodInfo(IDotNetObjectReference objectReference, string methodIdentifier) + { + var type = objectReference.Value.GetType(); + var assemblyMethods = _cachedMethodsByType.GetOrAdd(type, ScanTypeForCallableMethods); + if (assemblyMethods.TryGetValue(methodIdentifier, out var result)) + { + return result; + } + else + { + throw new ArgumentException($"The type '{type.Name}' does not contain a public invokable method with [{nameof(JSInvokableAttribute)}(\"{methodIdentifier}\")]."); + } + + static Dictionary ScanTypeForCallableMethods(Type type) + { + var result = new Dictionary(StringComparer.Ordinal); + var invokableMethods = type + .GetMethods(BindingFlags.Public | BindingFlags.Instance) + .Where(method => !method.ContainsGenericParameters && method.IsDefined(typeof(JSInvokableAttribute), inherit: false)); + + foreach (var method in invokableMethods) + { + var identifier = method.GetCustomAttribute(false).Identifier ?? method.Name; + var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); + + if (result.ContainsKey(identifier)) + { + throw new InvalidOperationException($"The type {type.Name} contains more than one " + + $"[JSInvokable] method with identifier '{identifier}'. All [JSInvokable] methods within the same " + + $"type must have different identifiers. You can pass a custom identifier as a parameter to " + + $"the [JSInvokable] attribute."); + } + + result.Add(identifier, (method, parameterTypes)); + } + + return result; } } @@ -312,35 +356,22 @@ namespace Microsoft.JSInterop.Infrastructure var result = new Dictionary(StringComparer.Ordinal); var invokableMethods = GetRequiredLoadedAssembly(assemblyKey) .GetExportedTypes() - .SelectMany(type => type.GetMethods( - BindingFlags.Public | - BindingFlags.DeclaredOnly | - BindingFlags.Instance | - BindingFlags.Static)) - .Where(method => method.IsDefined(typeof(JSInvokableAttribute), inherit: false)); + .SelectMany(type => type.GetMethods(BindingFlags.Public | BindingFlags.Static)) + .Where(method => !method.ContainsGenericParameters && method.IsDefined(typeof(JSInvokableAttribute), inherit: false)); foreach (var method in invokableMethods) { var identifier = method.GetCustomAttribute(false).Identifier ?? method.Name; var parameterTypes = method.GetParameters().Select(p => p.ParameterType).ToArray(); - try + if (result.ContainsKey(identifier)) { - result.Add(identifier, (method, parameterTypes)); - } - catch (ArgumentException) - { - if (result.ContainsKey(identifier)) - { - throw new InvalidOperationException($"The assembly '{assemblyKey.AssemblyName}' contains more than one " + - $"[JSInvokable] method with identifier '{identifier}'. All [JSInvokable] methods within the same " + - $"assembly must have different identifiers. You can pass a custom identifier as a parameter to " + - $"the [JSInvokable] attribute."); - } - else - { - throw; - } + throw new InvalidOperationException($"The assembly '{assemblyKey.AssemblyName}' contains more than one " + + $"[JSInvokable] method with identifier '{identifier}'. All [JSInvokable] methods within the same " + + $"assembly must have different identifiers. You can pass a custom identifier as a parameter to " + + $"the [JSInvokable] attribute."); } + + result.Add(identifier, (method, parameterTypes)); } return result; diff --git a/src/JSInterop/Microsoft.JSInterop/test/Infrastructure/DotNetDispatcherTest.cs b/src/JSInterop/Microsoft.JSInterop/test/Infrastructure/DotNetDispatcherTest.cs index 7e82a47a89..c85565d5f2 100644 --- a/src/JSInterop/Microsoft.JSInterop/test/Infrastructure/DotNetDispatcherTest.cs +++ b/src/JSInterop/Microsoft.JSInterop/test/Infrastructure/DotNetDispatcherTest.cs @@ -3,7 +3,6 @@ using System; using System.Linq; -using System.Runtime.ExceptionServices; using System.Text.Json; using System.Threading; using System.Threading.Tasks; @@ -70,7 +69,7 @@ namespace Microsoft.JSInterop.Infrastructure DotNetDispatcher.Invoke(new TestJSRuntime(), new DotNetInvocationInfo(thisAssemblyName, methodIdentifier, default, default), null); }); - Assert.Equal($"The assembly '{thisAssemblyName}' does not contain a public method with [JSInvokableAttribute(\"{methodIdentifier}\")].", ex.Message); + Assert.Equal($"The assembly '{thisAssemblyName}' does not contain a public invokable method with [JSInvokableAttribute(\"{methodIdentifier}\")].", ex.Message); } [Fact] @@ -355,6 +354,78 @@ namespace Microsoft.JSInterop.Infrastructure Assert.Equal("MY STRING", resultDto.StringVal); } + [Fact] + public void CanInvokeNonGenericInstanceMethodOnGenericType() + { + var jsRuntime = new TestJSRuntime(); + var targetInstance = new GenericType(); + jsRuntime.Invoke("_setup", + DotNetObjectReference.Create(targetInstance)); + var argsJson = "[\"hello world\"]"; + + // Act + var resultJson = DotNetDispatcher.Invoke(jsRuntime, new DotNetInvocationInfo(null, nameof(GenericType.EchoStringParameter), 1, default), argsJson); + + // Assert + Assert.Equal("\"hello world\"", resultJson); + } + + [Fact] + public void CanInvokeMethodsThatAcceptGenericParametersOnGenericTypes() + { + var jsRuntime = new TestJSRuntime(); + var targetInstance = new GenericType(); + jsRuntime.Invoke("_setup", + DotNetObjectReference.Create(targetInstance)); + var argsJson = "[\"hello world\"]"; + + // Act + var resultJson = DotNetDispatcher.Invoke(jsRuntime, new DotNetInvocationInfo(null, nameof(GenericType.EchoParameter), 1, default), argsJson); + + // Assert + Assert.Equal("\"hello world\"", resultJson); + } + + [Fact] + public void CannotInvokeStaticOpenGenericMethods() + { + var methodIdentifier = "StaticGenericMethod"; + var jsRuntime = new TestJSRuntime(); + + // Act + var ex = Assert.Throws(() => DotNetDispatcher.Invoke(jsRuntime, new DotNetInvocationInfo(thisAssemblyName, methodIdentifier, 0, default), "[7]")); + Assert.Contains($"The assembly '{thisAssemblyName}' does not contain a public invokable method with [{nameof(JSInvokableAttribute)}(\"{methodIdentifier}\")].", ex.Message); + } + + [Fact] + public void CannotInvokeInstanceOpenGenericMethods() + { + var methodIdentifier = "InstanceGenericMethod"; + var targetInstance = new GenericType(); + var jsRuntime = new TestJSRuntime(); + jsRuntime.Invoke("_setup", + DotNetObjectReference.Create(targetInstance)); + var argsJson = "[\"hello world\"]"; + + // Act + var ex = Assert.Throws(() => DotNetDispatcher.Invoke(jsRuntime, new DotNetInvocationInfo(null, methodIdentifier, 1, default), argsJson)); + Assert.Contains($"The type 'GenericType`1' does not contain a public invokable method with [{nameof(JSInvokableAttribute)}(\"{methodIdentifier}\")].", ex.Message); + } + + [Fact] + public void CannotInvokeMethodsWithGenericParameters_IfTypesDoNotMatch() + { + var jsRuntime = new TestJSRuntime(); + var targetInstance = new GenericType(); + jsRuntime.Invoke("_setup", + DotNetObjectReference.Create(targetInstance)); + var argsJson = "[\"hello world\"]"; + + // Act & Assert + Assert.Throws(() => + DotNetDispatcher.Invoke(jsRuntime, new DotNetInvocationInfo(null, nameof(GenericType.EchoParameter), 1, default), argsJson)); + } + [Fact] public void CannotInvokeWithFewerNumberOfParameters() { @@ -790,6 +861,18 @@ namespace Microsoft.JSInterop.Infrastructure } } + public class GenericType + { + [JSInvokable] public string EchoStringParameter(string input) => input; + [JSInvokable] public TValue EchoParameter(TValue input) => input; + } + + public class GenericMethodClass + { + [JSInvokable("StaticGenericMethod")] public static string StaticGenericMethod(TValue input) => input.ToString(); + [JSInvokable("InstanceGenericMethod")] public string GenericMethod(TValue input) => input.ToString(); + } + public class TestJSRuntime : JSInProcessRuntime { private TaskCompletionSource _nextInvocationTcs = new TaskCompletionSource(); From ed97d344c534069ce978497243708b0419a89192 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Fri, 6 Sep 2019 08:02:44 -0700 Subject: [PATCH 5/9] Rename file to make class \n\nCommit migrated from https://github.com/dotnet/extensions/commit/b6a290771fb6dd0a28e1a1cd91b8b0287dd812a8 --- src/Testing/src/xunit/FlakyAttribute.cs | 2 +- .../xunit/{FlakyTestDiscoverer.cs => FlakyTraitDiscoverer.cs} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/Testing/src/xunit/{FlakyTestDiscoverer.cs => FlakyTraitDiscoverer.cs} (95%) diff --git a/src/Testing/src/xunit/FlakyAttribute.cs b/src/Testing/src/xunit/FlakyAttribute.cs index 411435b74a..daceb964fd 100644 --- a/src/Testing/src/xunit/FlakyAttribute.cs +++ b/src/Testing/src/xunit/FlakyAttribute.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Testing /// to xunit.console.exe. Similarly, it can run only flaky tests using -trait "Flaky:AzP:OS:all=true" -trait "Flaky:AzP:OS:Darwin=true" /// /// - [TraitDiscoverer("Microsoft.AspNetCore.Testing." + nameof(FlakyTestDiscoverer), "Microsoft.AspNetCore.Testing")] + [TraitDiscoverer("Microsoft.AspNetCore.Testing." + nameof(FlakyTraitDiscoverer), "Microsoft.AspNetCore.Testing")] [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly)] public sealed class FlakyAttribute : Attribute, ITraitAttribute { diff --git a/src/Testing/src/xunit/FlakyTestDiscoverer.cs b/src/Testing/src/xunit/FlakyTraitDiscoverer.cs similarity index 95% rename from src/Testing/src/xunit/FlakyTestDiscoverer.cs rename to src/Testing/src/xunit/FlakyTraitDiscoverer.cs index 0c481e1c41..4e6bc27b1b 100644 --- a/src/Testing/src/xunit/FlakyTestDiscoverer.cs +++ b/src/Testing/src/xunit/FlakyTraitDiscoverer.cs @@ -6,7 +6,7 @@ using Xunit.Sdk; // Do not change this namespace without changing the usage in FlakyAttribute namespace Microsoft.AspNetCore.Testing { - public class FlakyTestDiscoverer : ITraitDiscoverer + public class FlakyTraitDiscoverer : ITraitDiscoverer { public IEnumerable> GetTraits(IAttributeInfo traitAttribute) { From b1987c75cbceb42c2da539d4df956a5204af07fd Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 11 Sep 2019 16:27:57 -0700 Subject: [PATCH 6/9] Add a workaround for xUnit bug We're currently experiencing a bug where conditional skips aren't working in VS. This is caused by https://github.com/xunit/xunit/issues/1782 \n\nCommit migrated from https://github.com/dotnet/extensions/commit/cbe90b849230d9b24f3152a44fa8d714c332b1e4 --- .../src/xunit/ConditionalTheoryDiscoverer.cs | 20 +++++ src/Testing/src/xunit/SkippedTestCase.cs | 7 +- .../WORKAROUND_SkippedDataRowTestCase.cs | 80 +++++++++++++++++++ 3 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/Testing/src/xunit/WORKAROUND_SkippedDataRowTestCase.cs diff --git a/src/Testing/src/xunit/ConditionalTheoryDiscoverer.cs b/src/Testing/src/xunit/ConditionalTheoryDiscoverer.cs index 764b613b16..e7f655a5be 100644 --- a/src/Testing/src/xunit/ConditionalTheoryDiscoverer.cs +++ b/src/Testing/src/xunit/ConditionalTheoryDiscoverer.cs @@ -1,6 +1,7 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; using System.Collections.Generic; using Xunit.Abstractions; using Xunit.Sdk; @@ -63,5 +64,24 @@ namespace Microsoft.AspNetCore.Testing base.CreateTestCasesForSkippedDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow, skipReason) : base.CreateTestCasesForDataRow(discoveryOptions, testMethod, theoryAttribute, dataRow); } + + protected override IEnumerable CreateTestCasesForSkippedDataRow( + ITestFrameworkDiscoveryOptions discoveryOptions, + ITestMethod testMethod, + IAttributeInfo theoryAttribute, + object[] dataRow, + string skipReason) + { + return new[] + { + new WORKAROUND_SkippedDataRowTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, skipReason, dataRow), + }; + } + + [Obsolete] + protected override IXunitTestCase CreateTestCaseForSkippedDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow, string skipReason) + { + return new WORKAROUND_SkippedDataRowTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, skipReason, dataRow); + } } } diff --git a/src/Testing/src/xunit/SkippedTestCase.cs b/src/Testing/src/xunit/SkippedTestCase.cs index b514c57209..0fdf166f2b 100644 --- a/src/Testing/src/xunit/SkippedTestCase.cs +++ b/src/Testing/src/xunit/SkippedTestCase.cs @@ -2,6 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Threading; +using System.Threading.Tasks; using Xunit.Abstractions; using Xunit.Sdk; @@ -33,8 +35,11 @@ namespace Microsoft.AspNetCore.Testing public override void Deserialize(IXunitSerializationInfo data) { - base.Deserialize(data); _skipReason = data.GetValue(nameof(_skipReason)); + + // We need to call base after reading our value, because Deserialize will call + // into GetSkipReason. + base.Deserialize(data); } public override void Serialize(IXunitSerializationInfo data) diff --git a/src/Testing/src/xunit/WORKAROUND_SkippedDataRowTestCase.cs b/src/Testing/src/xunit/WORKAROUND_SkippedDataRowTestCase.cs new file mode 100644 index 0000000000..a86f5645bf --- /dev/null +++ b/src/Testing/src/xunit/WORKAROUND_SkippedDataRowTestCase.cs @@ -0,0 +1,80 @@ +using System; +using System.ComponentModel; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + // This is a workaround for https://github.com/xunit/xunit/issues/1782 - as such, this code is a copy-paste + // from xUnit with the exception of fixing the bug. + // + // This will only work with [ConditionalTheory]. + internal class WORKAROUND_SkippedDataRowTestCase : XunitTestCase + { + string skipReason; + + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] + public WORKAROUND_SkippedDataRowTestCase() { } + + /// + /// Initializes a new instance of the class. + /// + /// The message sink used to send diagnostic messages + /// Default method display to use (when not customized). + /// The test method this test case belongs to. + /// The reason that this test case will be skipped + /// The arguments for the test method. + [Obsolete("Please call the constructor which takes TestMethodDisplayOptions")] + public WORKAROUND_SkippedDataRowTestCase(IMessageSink diagnosticMessageSink, + TestMethodDisplay defaultMethodDisplay, + ITestMethod testMethod, + string skipReason, + object[] testMethodArguments = null) + : this(diagnosticMessageSink, defaultMethodDisplay, TestMethodDisplayOptions.None, testMethod, skipReason, testMethodArguments) { } + + /// + /// Initializes a new instance of the class. + /// + /// The message sink used to send diagnostic messages + /// Default method display to use (when not customized). + /// Default method display options to use (when not customized). + /// The test method this test case belongs to. + /// The reason that this test case will be skipped + /// The arguments for the test method. + public WORKAROUND_SkippedDataRowTestCase(IMessageSink diagnosticMessageSink, + TestMethodDisplay defaultMethodDisplay, + TestMethodDisplayOptions defaultMethodDisplayOptions, + ITestMethod testMethod, + string skipReason, + object[] testMethodArguments = null) + : base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod, testMethodArguments) + { + this.skipReason = skipReason; + } + + /// + public override void Deserialize(IXunitSerializationInfo data) + { + // SkipReason has to be read before we call base.Deserialize, this is the workaround. + this.skipReason = data.GetValue("SkipReason"); + + base.Deserialize(data); + } + + /// + protected override string GetSkipReason(IAttributeInfo factAttribute) + { + return skipReason; + } + + /// + public override void Serialize(IXunitSerializationInfo data) + { + base.Serialize(data); + + data.AddValue("SkipReason", skipReason); + } + } +} From aadc979baf38b942fdf3f424e2b9a1ead5b8dffd Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Wed, 11 Sep 2019 16:31:38 -0700 Subject: [PATCH 7/9] Add AssemblyFixture to our test infra This is a feature that we're using in Templates and Blazor E2E tests to manage selenium. It's a general purpose kind of thing, so it makes sense to make it more general. This requires using the `[assembly: TestFramework()]`. Also fixed a bug here where this feature broke collection fixtures. \n\nCommit migrated from https://github.com/dotnet/extensions/commit/208d44a985fa4d8e13eb00515a44c5104c61b2b0 --- .../src/xunit/AspNetTestAssemblyRunner.cs | 83 +++++++++++++++++++ .../src/xunit/AspNetTestCollectionRunner.cs | 67 +++++++++++++++ src/Testing/src/xunit/AspNetTestFramework.cs | 20 +++++ .../src/xunit/AspNetTestFrameworkExecutor.cs | 26 ++++++ .../src/xunit/AssemblyFixtureAttribute.cs | 18 ++++ src/Testing/test/AssemblyFixtureTest.cs | 47 +++++++++++ src/Testing/test/Properties/AssemblyInfo.cs | 5 ++ src/Testing/test/TestAssemblyFixture.cs | 10 +++ src/Testing/test/TestCollectionFixture.cs | 10 +++ 9 files changed, 286 insertions(+) create mode 100644 src/Testing/src/xunit/AspNetTestAssemblyRunner.cs create mode 100644 src/Testing/src/xunit/AspNetTestCollectionRunner.cs create mode 100644 src/Testing/src/xunit/AspNetTestFramework.cs create mode 100644 src/Testing/src/xunit/AspNetTestFrameworkExecutor.cs create mode 100644 src/Testing/src/xunit/AssemblyFixtureAttribute.cs create mode 100644 src/Testing/test/AssemblyFixtureTest.cs create mode 100644 src/Testing/test/Properties/AssemblyInfo.cs create mode 100644 src/Testing/test/TestAssemblyFixture.cs create mode 100644 src/Testing/test/TestCollectionFixture.cs diff --git a/src/Testing/src/xunit/AspNetTestAssemblyRunner.cs b/src/Testing/src/xunit/AspNetTestAssemblyRunner.cs new file mode 100644 index 0000000000..48fbbbfa3b --- /dev/null +++ b/src/Testing/src/xunit/AspNetTestAssemblyRunner.cs @@ -0,0 +1,83 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + public class AspNetTestAssemblyRunner : XunitTestAssemblyRunner + { + private readonly Dictionary _assemblyFixtureMappings = new Dictionary(); + + public AspNetTestAssemblyRunner( + ITestAssembly testAssembly, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageSink executionMessageSink, + ITestFrameworkExecutionOptions executionOptions) + : base(testAssembly, testCases, diagnosticMessageSink, executionMessageSink, executionOptions) + { + } + + protected override async Task AfterTestAssemblyStartingAsync() + { + await base.AfterTestAssemblyStartingAsync(); + + // Find all the AssemblyFixtureAttributes on the test assembly + Aggregator.Run(() => + { + var fixturesAttributes = ((IReflectionAssemblyInfo)TestAssembly.Assembly) + .Assembly + .GetCustomAttributes(typeof(AssemblyFixtureAttribute), false) + .Cast() + .ToList(); + + // Instantiate all the fixtures + foreach (var fixtureAttribute in fixturesAttributes) + { + var ctorWithDiagnostics = fixtureAttribute.FixtureType.GetConstructor(new[] { typeof(IMessageSink) }); + if (ctorWithDiagnostics != null) + { + _assemblyFixtureMappings[fixtureAttribute.FixtureType] = Activator.CreateInstance(fixtureAttribute.FixtureType, DiagnosticMessageSink); + } + else + { + _assemblyFixtureMappings[fixtureAttribute.FixtureType] = Activator.CreateInstance(fixtureAttribute.FixtureType); + } + } + }); + } + + protected override Task BeforeTestAssemblyFinishedAsync() + { + // Dispose fixtures + foreach (var disposable in _assemblyFixtureMappings.Values.OfType()) + { + Aggregator.Run(disposable.Dispose); + } + + return base.BeforeTestAssemblyFinishedAsync(); + } + + protected override Task RunTestCollectionAsync( + IMessageBus messageBus, + ITestCollection testCollection, + IEnumerable testCases, + CancellationTokenSource cancellationTokenSource) + => new AspNetTestCollectionRunner( + _assemblyFixtureMappings, + testCollection, + testCases, + DiagnosticMessageSink, + messageBus, + TestCaseOrderer, + new ExceptionAggregator(Aggregator), + cancellationTokenSource).RunAsync(); + } +} diff --git a/src/Testing/src/xunit/AspNetTestCollectionRunner.cs b/src/Testing/src/xunit/AspNetTestCollectionRunner.cs new file mode 100644 index 0000000000..264cf769c6 --- /dev/null +++ b/src/Testing/src/xunit/AspNetTestCollectionRunner.cs @@ -0,0 +1,67 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + public class AspNetTestCollectionRunner : XunitTestCollectionRunner + { + private readonly IDictionary _assemblyFixtureMappings; + private readonly IMessageSink _diagnosticMessageSink; + + public AspNetTestCollectionRunner( + Dictionary assemblyFixtureMappings, + ITestCollection testCollection, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + ITestCaseOrderer testCaseOrderer, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(testCollection, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource) + { + _assemblyFixtureMappings = assemblyFixtureMappings; + _diagnosticMessageSink = diagnosticMessageSink; + } + + protected override async Task AfterTestCollectionStartingAsync() + { + await base.AfterTestCollectionStartingAsync(); + + // note: We pass the assembly fixtures into the runner as ICollectionFixture<> - this seems to work OK without any + // drawbacks. It's reasonable that we could add IAssemblyFixture<> and related plumbing if it ever became required. + // + // The reason for assembly fixture is when we want to start/stop something as the project scope - tests can only be + // in one test collection at a time. + foreach (var mapping in _assemblyFixtureMappings) + { + CollectionFixtureMappings.Add(mapping.Key, mapping.Value); + } + } + + protected override Task BeforeTestCollectionFinishedAsync() + { + // We need to remove the assembly fixtures so they won't get disposed. + foreach (var mapping in _assemblyFixtureMappings) + { + CollectionFixtureMappings.Remove(mapping.Key); + } + + return base.BeforeTestCollectionFinishedAsync(); + } + + protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases) + { + var caste = testCases.ToArray(); + var type = caste.First().GetType(); + return base.RunTestClassAsync(testClass, @class, testCases); + } + } +} diff --git a/src/Testing/src/xunit/AspNetTestFramework.cs b/src/Testing/src/xunit/AspNetTestFramework.cs new file mode 100644 index 0000000000..0a2dc1b21f --- /dev/null +++ b/src/Testing/src/xunit/AspNetTestFramework.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Reflection; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + public class AspNetTestFramework : XunitTestFramework + { + public AspNetTestFramework(IMessageSink messageSink) + : base(messageSink) + { + } + + protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName) + => new AspNetTestFrameworkExecutor(assemblyName, SourceInformationProvider, DiagnosticMessageSink); + } +} diff --git a/src/Testing/src/xunit/AspNetTestFrameworkExecutor.cs b/src/Testing/src/xunit/AspNetTestFrameworkExecutor.cs new file mode 100644 index 0000000000..b34f0b715e --- /dev/null +++ b/src/Testing/src/xunit/AspNetTestFrameworkExecutor.cs @@ -0,0 +1,26 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Reflection; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + public class AspNetTestFrameworkExecutor : XunitTestFrameworkExecutor + { + public AspNetTestFrameworkExecutor(AssemblyName assemblyName, ISourceInformationProvider sourceInformationProvider, IMessageSink diagnosticMessageSink) + : base(assemblyName, sourceInformationProvider, diagnosticMessageSink) + { + } + + protected override async void RunTestCases(IEnumerable testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions) + { + using (var assemblyRunner = new AspNetTestAssemblyRunner(TestAssembly, testCases, DiagnosticMessageSink, executionMessageSink, executionOptions)) + { + await assemblyRunner.RunAsync(); + } + } + } +} diff --git a/src/Testing/src/xunit/AssemblyFixtureAttribute.cs b/src/Testing/src/xunit/AssemblyFixtureAttribute.cs new file mode 100644 index 0000000000..c3b9eba31d --- /dev/null +++ b/src/Testing/src/xunit/AssemblyFixtureAttribute.cs @@ -0,0 +1,18 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.AspNetCore.Testing +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public class AssemblyFixtureAttribute : Attribute + { + public AssemblyFixtureAttribute(Type fixtureType) + { + FixtureType = fixtureType; + } + + public Type FixtureType { get; private set; } + } +} diff --git a/src/Testing/test/AssemblyFixtureTest.cs b/src/Testing/test/AssemblyFixtureTest.cs new file mode 100644 index 0000000000..a5fa73019a --- /dev/null +++ b/src/Testing/test/AssemblyFixtureTest.cs @@ -0,0 +1,47 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.AspNetCore.Testing +{ + // We include a collection and assembly fixture to verify that they both still work. + [Collection("MyCollection")] + [TestCaseOrderer("Microsoft.AspNetCore.Testing.AlphabeticalOrderer", "Microsoft.AspNetCore.Testing.Tests")] + public class AssemblyFixtureTest + { + public AssemblyFixtureTest(TestAssemblyFixture assemblyFixture, TestCollectionFixture collectionFixture) + { + AssemblyFixture = assemblyFixture; + CollectionFixture = collectionFixture; + } + + public TestAssemblyFixture AssemblyFixture { get; } + public TestCollectionFixture CollectionFixture { get; } + + [Fact] + public void A() + { + Assert.NotNull(AssemblyFixture); + Assert.Equal(0, AssemblyFixture.Count); + + Assert.NotNull(CollectionFixture); + Assert.Equal(0, CollectionFixture.Count); + + AssemblyFixture.Count++; + CollectionFixture.Count++; + } + + [Fact] + public void B() + { + Assert.Equal(1, AssemblyFixture.Count); + Assert.Equal(1, CollectionFixture.Count); + } + } + + [CollectionDefinition("MyCollection", DisableParallelization = true)] + public class MyCollection : ICollectionFixture + { + } +} diff --git a/src/Testing/test/Properties/AssemblyInfo.cs b/src/Testing/test/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..4dba8d157e --- /dev/null +++ b/src/Testing/test/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using Microsoft.AspNetCore.Testing; +using Xunit; + +[assembly: AssemblyFixture(typeof(TestAssemblyFixture))] +[assembly: TestFramework("Microsoft.AspNetCore.Testing.AspNetTestFramework", "Microsoft.AspNetCore.Testing")] diff --git a/src/Testing/test/TestAssemblyFixture.cs b/src/Testing/test/TestAssemblyFixture.cs new file mode 100644 index 0000000000..44308160bd --- /dev/null +++ b/src/Testing/test/TestAssemblyFixture.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Testing +{ + public class TestAssemblyFixture + { + public int Count { get; set; } + } +} diff --git a/src/Testing/test/TestCollectionFixture.cs b/src/Testing/test/TestCollectionFixture.cs new file mode 100644 index 0000000000..b9aed01e41 --- /dev/null +++ b/src/Testing/test/TestCollectionFixture.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNetCore.Testing +{ + public class TestCollectionFixture + { + public int Count { get; set; } + } +} From ddde4faf4f43a2070353fee4d6f3d0c09aaa586d Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Mon, 16 Sep 2019 13:33:09 -0700 Subject: [PATCH 8/9] Refactor xUnit extensibility Adds our own hook for before/after logic that's more usable, called `ITestMethodLifecycle`. This provides access to a context object including the information about the test and the output helper. This can be implemented by attributes or by the class itself. The goal (and result) of this, is that we have a single *test executor* extensibility point that provides all of the features we need. We should use this everywhere we need features xUnit doesn't have. Adding a new extensibility point (`ITestMethodLifecycle`) allows us to do this without turning all of these features into a giant monolith. --- Also updated our existing extensibility to use this new hook. I did as much cleanup as a could to remove duplication from logging and keep it loosly coupled. I didn't want to tease this apart completely because the scope of this PR is already pretty large. \n\nCommit migrated from https://github.com/dotnet/extensions/commit/1b10284a47a4f58d69f3ee1feb232ecbf77168ee --- src/Testing/src/ITestMethodLifecycle.cs | 23 +++ src/Testing/src/RepeatAttribute.cs | 27 ++++ src/Testing/src/RepeatContext.cs | 27 ++++ src/Testing/src/ShortClassNameAttribute.cs | 17 +++ src/Testing/src/TestContext.cs | 44 ++++++ src/Testing/src/TestFileOutputContext.cs | 140 ++++++++++++++++++ .../src/TestOutputDirectoryAttribute.cs | 20 +++ src/Testing/src/xunit/AspNetTestCaseRunner.cs | 33 +++++ .../src/xunit/AspNetTestClassRunner.cs | 44 ++++++ .../src/xunit/AspNetTestCollectionRunner.cs | 14 +- src/Testing/src/xunit/AspNetTestInvoker.cs | 84 +++++++++++ .../src/xunit/AspNetTestMethodRunner.cs | 73 +++++++++ src/Testing/src/xunit/AspNetTestRunner.cs | 78 ++++++++++ .../src/xunit/AspNetTheoryTestCaseRunner.cs | 33 +++++ src/Testing/test/Properties/AssemblyInfo.cs | 1 + src/Testing/test/RepeatTest.cs | 43 ++++++ src/Testing/test/TestContextTest.cs | 83 +++++++++++ 17 files changed, 781 insertions(+), 3 deletions(-) create mode 100644 src/Testing/src/ITestMethodLifecycle.cs create mode 100644 src/Testing/src/RepeatAttribute.cs create mode 100644 src/Testing/src/RepeatContext.cs create mode 100644 src/Testing/src/ShortClassNameAttribute.cs create mode 100644 src/Testing/src/TestContext.cs create mode 100644 src/Testing/src/TestFileOutputContext.cs create mode 100644 src/Testing/src/TestOutputDirectoryAttribute.cs create mode 100644 src/Testing/src/xunit/AspNetTestCaseRunner.cs create mode 100644 src/Testing/src/xunit/AspNetTestClassRunner.cs create mode 100644 src/Testing/src/xunit/AspNetTestInvoker.cs create mode 100644 src/Testing/src/xunit/AspNetTestMethodRunner.cs create mode 100644 src/Testing/src/xunit/AspNetTestRunner.cs create mode 100644 src/Testing/src/xunit/AspNetTheoryTestCaseRunner.cs create mode 100644 src/Testing/test/RepeatTest.cs create mode 100644 src/Testing/test/TestContextTest.cs diff --git a/src/Testing/src/ITestMethodLifecycle.cs b/src/Testing/src/ITestMethodLifecycle.cs new file mode 100644 index 0000000000..d22779b6dd --- /dev/null +++ b/src/Testing/src/ITestMethodLifecycle.cs @@ -0,0 +1,23 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.AspNetCore.Testing +{ + /// + /// Defines a lifecycle for attributes or classes that want to know about tests starting + /// or ending. Implement this on a test class, or attribute at the method/class/assembly level. + /// + /// + /// Requires defining as the test framework. + /// + public interface ITestMethodLifecycle + { + Task OnTestStartAsync(TestContext context, CancellationToken cancellationToken); + + Task OnTestEndAsync(TestContext context, Exception exception, CancellationToken cancellationToken); + } +} diff --git a/src/Testing/src/RepeatAttribute.cs b/src/Testing/src/RepeatAttribute.cs new file mode 100644 index 0000000000..7bf3073734 --- /dev/null +++ b/src/Testing/src/RepeatAttribute.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.ComponentModel; + +namespace Microsoft.AspNetCore.Testing +{ + /// + /// Runs a test multiple times to stress flaky tests that are believed to be fixed. + /// This can be used on an assembly, class, or method name. Requires using the AspNetCore test framework. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)] + public class RepeatAttribute : Attribute + { + public RepeatAttribute(int runCount = 10) + { + RunCount = runCount; + } + + /// + /// The number of times to run a test. + /// + public int RunCount { get; } + } +} diff --git a/src/Testing/src/RepeatContext.cs b/src/Testing/src/RepeatContext.cs new file mode 100644 index 0000000000..d76a0f177e --- /dev/null +++ b/src/Testing/src/RepeatContext.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Threading; + +namespace Microsoft.AspNetCore.Testing +{ + public class RepeatContext + { + private static AsyncLocal _current = new AsyncLocal(); + + public static RepeatContext Current + { + get => _current.Value; + internal set => _current.Value = value; + } + + public RepeatContext(int limit) + { + Limit = limit; + } + + public int Limit { get; } + + public int CurrentIteration { get; set; } + } +} diff --git a/src/Testing/src/ShortClassNameAttribute.cs b/src/Testing/src/ShortClassNameAttribute.cs new file mode 100644 index 0000000000..6a36575d70 --- /dev/null +++ b/src/Testing/src/ShortClassNameAttribute.cs @@ -0,0 +1,17 @@ +// Copyright(c) .NET Foundation.All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.AspNetCore.Testing +{ + /// + /// Used to specify that should used the + /// unqualified class name. This is needed when a fully-qualified class name exceeds + /// max path for logging. + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)] + public class ShortClassNameAttribute : Attribute + { + } +} diff --git a/src/Testing/src/TestContext.cs b/src/Testing/src/TestContext.cs new file mode 100644 index 0000000000..a702d71ecf --- /dev/null +++ b/src/Testing/src/TestContext.cs @@ -0,0 +1,44 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Reflection; +using Xunit.Abstractions; + +namespace Microsoft.AspNetCore.Testing +{ + /// + /// Provides access to contextual information about the running tests. Get access by + /// implementing . + /// + /// + /// Requires defining as the test framework. + /// + public sealed class TestContext + { + private Lazy _files; + + public TestContext( + Type testClass, + object[] constructorArguments, + MethodInfo testMethod, + object[] methodArguments, + ITestOutputHelper output) + { + TestClass = testClass; + ConstructorArguments = constructorArguments; + TestMethod = testMethod; + MethodArguments = methodArguments; + Output = output; + + _files = new Lazy(() => new TestFileOutputContext(this)); + } + + public Type TestClass { get; } + public MethodInfo TestMethod { get; } + public object[] ConstructorArguments { get; } + public object[] MethodArguments { get; } + public ITestOutputHelper Output { get; } + public TestFileOutputContext FileOutput => _files.Value; + } +} diff --git a/src/Testing/src/TestFileOutputContext.cs b/src/Testing/src/TestFileOutputContext.cs new file mode 100644 index 0000000000..496a1379fb --- /dev/null +++ b/src/Testing/src/TestFileOutputContext.cs @@ -0,0 +1,140 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace Microsoft.AspNetCore.Testing +{ + /// + /// Provides access to file storage for the running test. Get access by + /// implementing , and accessing . + /// + /// + /// Requires defining as the test framework. + /// + public sealed class TestFileOutputContext + { + private static char[] InvalidFileChars = new char[] + { + '\"', '<', '>', '|', '\0', + (char)1, (char)2, (char)3, (char)4, (char)5, (char)6, (char)7, (char)8, (char)9, (char)10, + (char)11, (char)12, (char)13, (char)14, (char)15, (char)16, (char)17, (char)18, (char)19, (char)20, + (char)21, (char)22, (char)23, (char)24, (char)25, (char)26, (char)27, (char)28, (char)29, (char)30, + (char)31, ':', '*', '?', '\\', '/', ' ', (char)127 + }; + + private readonly TestContext _parent; + + public TestFileOutputContext(TestContext parent) + { + _parent = parent; + + TestName = GetTestMethodName(parent.TestMethod, parent.MethodArguments); + TestClassName = GetTestClassName(parent.TestClass); + + AssemblyOutputDirectory = GetAssemblyBaseDirectory(_parent.TestClass.Assembly); + if (!string.IsNullOrEmpty(AssemblyOutputDirectory)) + { + TestClassOutputDirectory = Path.Combine(AssemblyOutputDirectory, TestClassName); + } + } + + public string TestName { get; } + + public string TestClassName { get; } + + public string AssemblyOutputDirectory { get; } + + public string TestClassOutputDirectory { get; } + + public string GetUniqueFileName(string prefix, string extension) + { + if (prefix == null) + { + throw new ArgumentNullException(nameof(prefix)); + } + + if (extension != null && !extension.StartsWith(".", StringComparison.Ordinal)) + { + throw new ArgumentException("The extension must start with '.' if one is provided.", nameof(extension)); + } + + var path = Path.Combine(TestClassOutputDirectory, $"{prefix}{extension}"); + + var i = 1; + while (File.Exists(path)) + { + path = Path.Combine(TestClassOutputDirectory, $"{prefix}{i++}{extension}"); + } + + return path; + } + + // Gets the output directory without appending the TFM or assembly name. + public static string GetOutputDirectory(Assembly assembly) + { + var attribute = assembly.GetCustomAttributes().OfType().FirstOrDefault(); + return attribute?.BaseDirectory; + } + + public static string GetAssemblyBaseDirectory(Assembly assembly, string baseDirectory = null) + { + var attribute = assembly.GetCustomAttributes().OfType().FirstOrDefault(); + baseDirectory = baseDirectory ?? attribute?.BaseDirectory; + if (string.IsNullOrEmpty(baseDirectory)) + { + return string.Empty; + } + + return Path.Combine(baseDirectory, assembly.GetName().Name, attribute.TargetFramework); + } + + public static string GetTestClassName(Type type) + { + var shortNameAttribute = + type.GetCustomAttribute() ?? + type.Assembly.GetCustomAttribute(); + var name = shortNameAttribute == null ? type.FullName : type.Name; + + // Try to shorten the class name using the assembly name + var assemblyName = type.Assembly.GetName().Name; + if (name.StartsWith(assemblyName + ".")) + { + name = name.Substring(assemblyName.Length + 1); + } + + return name; + } + + public static string GetTestMethodName(MethodInfo method, object[] arguments) + { + var name = arguments.Aggregate(method.Name, (a, b) => $"{a}-{(b ?? "null")}"); + return RemoveIllegalFileChars(name); + } + + public static string RemoveIllegalFileChars(string s) + { + var sb = new StringBuilder(); + + foreach (var c in s) + { + if (InvalidFileChars.Contains(c)) + { + if (sb.Length > 0 && sb[sb.Length - 1] != '_') + { + sb.Append('_'); + } + } + else + { + sb.Append(c); + } + } + return sb.ToString(); + } + } +} diff --git a/src/Testing/src/TestOutputDirectoryAttribute.cs b/src/Testing/src/TestOutputDirectoryAttribute.cs new file mode 100644 index 0000000000..4ae8cea054 --- /dev/null +++ b/src/Testing/src/TestOutputDirectoryAttribute.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.AspNetCore.Testing +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false, Inherited = true)] + public class TestOutputDirectoryAttribute : Attribute + { + public TestOutputDirectoryAttribute(string targetFramework, string baseDirectory = null) + { + TargetFramework = targetFramework; + BaseDirectory = baseDirectory; + } + + public string BaseDirectory { get; } + public string TargetFramework { get; } + } +} diff --git a/src/Testing/src/xunit/AspNetTestCaseRunner.cs b/src/Testing/src/xunit/AspNetTestCaseRunner.cs new file mode 100644 index 0000000000..42773db212 --- /dev/null +++ b/src/Testing/src/xunit/AspNetTestCaseRunner.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + internal class AspNetTestCaseRunner : XunitTestCaseRunner + { + public AspNetTestCaseRunner( + IXunitTestCase testCase, + string displayName, + string skipReason, + object[] constructorArguments, + object[] testMethodArguments, + IMessageBus messageBus, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(testCase, displayName, skipReason, constructorArguments, testMethodArguments, messageBus, aggregator, cancellationTokenSource) + { + } + + protected override XunitTestRunner CreateTestRunner(ITest test, IMessageBus messageBus, Type testClass, object[] constructorArguments, MethodInfo testMethod, object[] testMethodArguments, string skipReason, IReadOnlyList beforeAfterAttributes, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) + { + return new AspNetTestRunner(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource); + } + } +} diff --git a/src/Testing/src/xunit/AspNetTestClassRunner.cs b/src/Testing/src/xunit/AspNetTestClassRunner.cs new file mode 100644 index 0000000000..bbefa37427 --- /dev/null +++ b/src/Testing/src/xunit/AspNetTestClassRunner.cs @@ -0,0 +1,44 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + internal class AspNetTestClassRunner : XunitTestClassRunner + { + public AspNetTestClassRunner( + ITestClass testClass, + IReflectionTypeInfo @class, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + ITestCaseOrderer testCaseOrderer, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource, + IDictionary collectionFixtureMappings) + : base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource, collectionFixtureMappings) + { + } + + protected override Task RunTestMethodAsync(ITestMethod testMethod, IReflectionMethodInfo method, IEnumerable testCases, object[] constructorArguments) + { + var runner = new AspNetTestMethodRunner( + testMethod, + Class, + method, + testCases, + DiagnosticMessageSink, + MessageBus, + new ExceptionAggregator(Aggregator), + CancellationTokenSource, + constructorArguments); + return runner.RunAsync(); + } + } +} diff --git a/src/Testing/src/xunit/AspNetTestCollectionRunner.cs b/src/Testing/src/xunit/AspNetTestCollectionRunner.cs index 264cf769c6..522cbd4624 100644 --- a/src/Testing/src/xunit/AspNetTestCollectionRunner.cs +++ b/src/Testing/src/xunit/AspNetTestCollectionRunner.cs @@ -59,9 +59,17 @@ namespace Microsoft.AspNetCore.Testing protected override Task RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable testCases) { - var caste = testCases.ToArray(); - var type = caste.First().GetType(); - return base.RunTestClassAsync(testClass, @class, testCases); + var runner = new AspNetTestClassRunner( + testClass, + @class, + testCases, + DiagnosticMessageSink, + MessageBus, + TestCaseOrderer, + new ExceptionAggregator(Aggregator), + CancellationTokenSource, + CollectionFixtureMappings); + return runner.RunAsync(); } } } diff --git a/src/Testing/src/xunit/AspNetTestInvoker.cs b/src/Testing/src/xunit/AspNetTestInvoker.cs new file mode 100644 index 0000000000..a764db6622 --- /dev/null +++ b/src/Testing/src/xunit/AspNetTestInvoker.cs @@ -0,0 +1,84 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + internal class AspNetTestInvoker : XunitTestInvoker + { + public AspNetTestInvoker( + ITest test, + IMessageBus messageBus, + Type testClass, + object[] constructorArguments, + MethodInfo testMethod, + object[] testMethodArguments, + IReadOnlyList beforeAfterAttributes, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, beforeAfterAttributes, aggregator, cancellationTokenSource) + { + } + + protected override async Task InvokeTestMethodAsync(object testClassInstance) + { + var output = new TestOutputHelper(); + output.Initialize(MessageBus, Test); + + var context = new TestContext(TestClass, ConstructorArguments, TestMethod, TestMethodArguments, output); + var lifecycleHooks = GetLifecycleHooks(testClassInstance, TestClass, TestMethod); + + await Aggregator.RunAsync(async () => + { + foreach (var lifecycleHook in lifecycleHooks) + { + await lifecycleHook.OnTestStartAsync(context, CancellationTokenSource.Token); + } + }); + + var time = await base.InvokeTestMethodAsync(testClassInstance); + + await Aggregator.RunAsync(async () => + { + var exception = Aggregator.HasExceptions ? Aggregator.ToException() : null; + foreach (var lifecycleHook in lifecycleHooks) + { + await lifecycleHook.OnTestEndAsync(context, exception, CancellationTokenSource.Token); + } + }); + + return time; + } + + private static IEnumerable GetLifecycleHooks(object testClassInstance, Type testClass, MethodInfo testMethod) + { + foreach (var attribute in testMethod.GetCustomAttributes(inherit: true).OfType()) + { + yield return attribute; + } + + if (testClassInstance is ITestMethodLifecycle instance) + { + yield return instance; + } + + foreach (var attribute in testClass.GetCustomAttributes(inherit: true).OfType()) + { + yield return attribute; + } + + foreach (var attribute in testClass.Assembly.GetCustomAttributes(inherit: true).OfType()) + { + yield return attribute; + } + } + } +} diff --git a/src/Testing/src/xunit/AspNetTestMethodRunner.cs b/src/Testing/src/xunit/AspNetTestMethodRunner.cs new file mode 100644 index 0000000000..e238d0769d --- /dev/null +++ b/src/Testing/src/xunit/AspNetTestMethodRunner.cs @@ -0,0 +1,73 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Testing.xunit; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + internal class AspNetTestMethodRunner : XunitTestMethodRunner + { + private readonly object[] _constructorArguments; + private readonly IMessageSink _diagnosticMessageSink; + + public AspNetTestMethodRunner( + ITestMethod testMethod, + IReflectionTypeInfo @class, + IReflectionMethodInfo method, + IEnumerable testCases, + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource, + object[] constructorArguments) + : base(testMethod, @class, method, testCases, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource, constructorArguments) + { + _diagnosticMessageSink = diagnosticMessageSink; + _constructorArguments = constructorArguments; + } + + protected override Task RunTestCaseAsync(IXunitTestCase testCase) + { + if (testCase.GetType() == typeof(XunitTestCase)) + { + // If we get here this is a 'regular' test case, not something that represents a skipped test. + // + // We can take control of it's invocation thusly. + var runner = new AspNetTestCaseRunner( + testCase, + testCase.DisplayName, + testCase.SkipReason, + _constructorArguments, + testCase.TestMethodArguments, + MessageBus, + new ExceptionAggregator(Aggregator), + CancellationTokenSource); + return runner.RunAsync(); + } + + if (testCase.GetType() == typeof(XunitTheoryTestCase)) + { + // If we get here this is a 'regular' theory test case, not something that represents a skipped test. + // + // We can take control of it's invocation thusly. + var runner = new AspNetTheoryTestCaseRunner( + testCase, + testCase.DisplayName, + testCase.SkipReason, + _constructorArguments, + _diagnosticMessageSink, + MessageBus, + new ExceptionAggregator(Aggregator), + CancellationTokenSource); + return runner.RunAsync(); + } + + return base.RunTestCaseAsync(testCase); + } + } +} diff --git a/src/Testing/src/xunit/AspNetTestRunner.cs b/src/Testing/src/xunit/AspNetTestRunner.cs new file mode 100644 index 0000000000..2786a866b4 --- /dev/null +++ b/src/Testing/src/xunit/AspNetTestRunner.cs @@ -0,0 +1,78 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing +{ + internal class AspNetTestRunner : XunitTestRunner + { + public AspNetTestRunner( + ITest test, + IMessageBus messageBus, + Type testClass, + object[] constructorArguments, + MethodInfo testMethod, + object[] testMethodArguments, + string skipReason, + IReadOnlyList beforeAfterAttributes, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource) + { + } + + protected override async Task InvokeTestMethodAsync(ExceptionAggregator aggregator) + { + var repeatAttribute = GetRepeatAttribute(TestMethod); + if (repeatAttribute == null) + { + return await InvokeTestMethodCoreAsync(aggregator); + } + + var repeatContext = new RepeatContext(repeatAttribute.RunCount); + RepeatContext.Current = repeatContext; + + var timeTaken = 0.0M; + for (repeatContext.CurrentIteration = 0; repeatContext.CurrentIteration < repeatContext.Limit; repeatContext.CurrentIteration++) + { + timeTaken = await InvokeTestMethodCoreAsync(aggregator); + if (aggregator.HasExceptions) + { + return timeTaken; + } + } + + return timeTaken; + } + + private Task InvokeTestMethodCoreAsync(ExceptionAggregator aggregator) + { + var invoker = new AspNetTestInvoker(Test, MessageBus, TestClass, ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator, CancellationTokenSource); + return invoker.RunAsync(); + } + + private RepeatAttribute GetRepeatAttribute(MethodInfo methodInfo) + { + var attributeCandidate = methodInfo.GetCustomAttribute(); + if (attributeCandidate != null) + { + return attributeCandidate; + } + + attributeCandidate = methodInfo.DeclaringType.GetCustomAttribute(); + if (attributeCandidate != null) + { + return attributeCandidate; + } + + return methodInfo.DeclaringType.Assembly.GetCustomAttribute(); + } + } +} diff --git a/src/Testing/src/xunit/AspNetTheoryTestCaseRunner.cs b/src/Testing/src/xunit/AspNetTheoryTestCaseRunner.cs new file mode 100644 index 0000000000..a09a17cf69 --- /dev/null +++ b/src/Testing/src/xunit/AspNetTheoryTestCaseRunner.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Threading; +using Xunit.Abstractions; +using Xunit.Sdk; + +namespace Microsoft.AspNetCore.Testing.xunit +{ + internal class AspNetTheoryTestCaseRunner : XunitTheoryTestCaseRunner + { + public AspNetTheoryTestCaseRunner( + IXunitTestCase testCase, + string displayName, + string skipReason, + object[] constructorArguments, + IMessageSink diagnosticMessageSink, + IMessageBus messageBus, + ExceptionAggregator aggregator, + CancellationTokenSource cancellationTokenSource) + : base(testCase, displayName, skipReason, constructorArguments, diagnosticMessageSink, messageBus, aggregator, cancellationTokenSource) + { + } + + protected override XunitTestRunner CreateTestRunner(ITest test, IMessageBus messageBus, Type testClass, object[] constructorArguments, MethodInfo testMethod, object[] testMethodArguments, string skipReason, IReadOnlyList beforeAfterAttributes, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) + { + return new AspNetTestRunner(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource); + } + } +} diff --git a/src/Testing/test/Properties/AssemblyInfo.cs b/src/Testing/test/Properties/AssemblyInfo.cs index 4dba8d157e..d585b5ed95 100644 --- a/src/Testing/test/Properties/AssemblyInfo.cs +++ b/src/Testing/test/Properties/AssemblyInfo.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Testing; using Xunit; +[assembly: Repeat(1)] [assembly: AssemblyFixture(typeof(TestAssemblyFixture))] [assembly: TestFramework("Microsoft.AspNetCore.Testing.AspNetTestFramework", "Microsoft.AspNetCore.Testing")] diff --git a/src/Testing/test/RepeatTest.cs b/src/Testing/test/RepeatTest.cs new file mode 100644 index 0000000000..0d995fad59 --- /dev/null +++ b/src/Testing/test/RepeatTest.cs @@ -0,0 +1,43 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using Xunit; + +namespace Microsoft.AspNetCore.Testing +{ + [Repeat] + public class RepeatTest + { + public static int _runCount = 0; + + [Fact] + [Repeat(5)] + public void RepeatLimitIsSetCorrectly() + { + Assert.Equal(5, RepeatContext.Current.Limit); + } + + [Fact] + [Repeat(5)] + public void RepeatRunsTestSpecifiedNumberOfTimes() + { + Assert.Equal(RepeatContext.Current.CurrentIteration, _runCount); + _runCount++; + } + + [Fact] + public void RepeatCanBeSetOnClass() + { + Assert.Equal(10, RepeatContext.Current.Limit); + } + } + + public class LoggedTestXunitRepeatAssemblyTests + { + [Fact] + public void RepeatCanBeSetOnAssembly() + { + Assert.Equal(1, RepeatContext.Current.Limit); + } + } +} diff --git a/src/Testing/test/TestContextTest.cs b/src/Testing/test/TestContextTest.cs new file mode 100644 index 0000000000..944d706477 --- /dev/null +++ b/src/Testing/test/TestContextTest.cs @@ -0,0 +1,83 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Threading; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNetCore.Testing +{ + public class TestContextTest : ITestMethodLifecycle + { + public TestContext Context { get; private set; } + + [Fact] + public void FullName_IsUsed_ByDefault() + { + Assert.Equal(GetType().FullName, Context.FileOutput.TestClassName); + } + + Task ITestMethodLifecycle.OnTestStartAsync(TestContext context, CancellationToken cancellationToken) + { + Context = context; + return Task.CompletedTask; + } + + Task ITestMethodLifecycle.OnTestEndAsync(TestContext context, Exception exception, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } +} + +namespace Microsoft.AspNetCore.Testing.Tests +{ + public class TestContextNameShorteningTest : ITestMethodLifecycle + { + public TestContext Context { get; private set; } + + [Fact] + public void NameIsShortenedWhenAssemblyNameIsAPrefix() + { + Assert.Equal(GetType().Name, Context.FileOutput.TestClassName); + } + + Task ITestMethodLifecycle.OnTestStartAsync(TestContext context, CancellationToken cancellationToken) + { + Context = context; + return Task.CompletedTask; + } + + Task ITestMethodLifecycle.OnTestEndAsync(TestContext context, Exception exception, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } +} + +namespace Microsoft.AspNetCore.Testing +{ + [ShortClassName] + public class TestContextTestClassShortNameAttributeTest : ITestMethodLifecycle + { + public TestContext Context { get; private set; } + + [Fact] + public void ShortClassNameUsedWhenShortClassNameAttributeSpecified() + { + Assert.Equal(GetType().Name, Context.FileOutput.TestClassName); + } + + Task ITestMethodLifecycle.OnTestStartAsync(TestContext context, CancellationToken cancellationToken) + { + Context = context; + return Task.CompletedTask; + } + + Task ITestMethodLifecycle.OnTestEndAsync(TestContext context, Exception exception, CancellationToken cancellationToken) + { + return Task.CompletedTask; + } + } +} From 5114f2f1a25a712112b4e23e2dae99dfa9b91dac Mon Sep 17 00:00:00 2001 From: Pranav K Date: Mon, 23 Sep 2019 09:42:48 -0700 Subject: [PATCH 9/9] Add null check for DotNetObjectReference (dotnet/extensions#2372) \n\nCommit migrated from https://github.com/dotnet/extensions/commit/45776ac25c750bc98522f7d8bdbba61bcc7540d4 --- .../Microsoft.JSInterop/src/DotNetObjectReference.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/JSInterop/Microsoft.JSInterop/src/DotNetObjectReference.cs b/src/JSInterop/Microsoft.JSInterop/src/DotNetObjectReference.cs index 989d8062bb..53217936d6 100644 --- a/src/JSInterop/Microsoft.JSInterop/src/DotNetObjectReference.cs +++ b/src/JSInterop/Microsoft.JSInterop/src/DotNetObjectReference.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System; + namespace Microsoft.JSInterop { /// @@ -15,6 +17,11 @@ namespace Microsoft.JSInterop /// An instance of . public static DotNetObjectReference Create(TValue value) where TValue : class { + if (value is null) + { + throw new ArgumentNullException(nameof(value)); + } + return new DotNetObjectReference(value); } }