Merge branchess

\n\nCommit migrated from 9c6c47ff99
This commit is contained in:
wtgodbe 2019-11-22 12:46:11 -08:00
commit f7540812ce
87 changed files with 1780 additions and 161 deletions

View File

@ -1,15 +1,15 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.Extensions.Configuration.KeyPerFile.netstandard2.0.cs" />
<Reference Include="Microsoft.Extensions.Configuration" />
<Reference Include="Microsoft.Extensions.FileProviders.Physical" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.Extensions.Configuration.KeyPerFile.netcoreapp3.0.cs" />
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.Extensions.Configuration.KeyPerFile.netcoreapp.cs" />
<Reference Include="Microsoft.Extensions.Configuration" />
<Reference Include="Microsoft.Extensions.FileProviders.Physical" />
</ItemGroup>

View File

@ -2,8 +2,8 @@
<PropertyGroup>
<Description>Configuration provider that uses files in a directory for Microsoft.Extensions.Configuration.</Description>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<IsPackable>true</IsPackable>
<IsShipping>true</IsShipping>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

View File

@ -1,14 +1,14 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.Extensions.FileProviders.Embedded.netstandard2.0.cs" />
<Reference Include="Microsoft.Extensions.FileProviders.Abstractions" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.Extensions.FileProviders.Embedded.netcoreapp3.0.cs" />
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.Extensions.FileProviders.Embedded.netcoreapp.cs" />
<Reference Include="Microsoft.Extensions.FileProviders.Abstractions" />
</ItemGroup>
</Project>

View File

@ -3,10 +3,10 @@
<PropertyGroup>
<RootNamespace>Microsoft.Extensions.FileProviders</RootNamespace>
<Description>File provider for files in embedded resources for Microsoft.Extensions.FileProviders.</Description>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<NuspecFile>$(MSBuildProjectName).multitarget.nuspec</NuspecFile>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">netcoreapp3.0</TargetFrameworks>
<NuspecFile Condition="'$(DotNetBuildFromSource)' == 'true'">$(MSBuildProjectName).netcoreapp3.0.nuspec</NuspecFile>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<NuspecFile Condition="'$(DotNetBuildFromSource)' == 'true'">$(MSBuildProjectName).netcoreapp.nuspec</NuspecFile>
<IsPackable>true</IsPackable>
<IsShipping>true</IsShipping>
</PropertyGroup>
@ -27,9 +27,7 @@
<ItemGroup>
<NuspecProperty Include="AssemblyName=$(AssemblyName)" />
<NuspecProperty Include="OutputBinary=$(OutputPath)**\$(AssemblyName).dll" />
<NuspecProperty Include="OutputSymbol=$(OutputPath)**\$(AssemblyName).pdb" />
<NuspecProperty Include="OutputDocumentation=$(OutputPath)**\$(AssemblyName).xml" />
<NuspecProperty Include="OutputPath=$(OutputPath)" />
<NuspecProperty Include="TaskAssemblyNetStandard=$(ArtifactsDir)bin\$(AssemblyName).Manifest.Task\$(Configuration)\netstandard2.0\$(AssemblyName).Manifest.Task.dll"/>
<NuspecProperty Include="TaskSymbolNetStandard=$(ArtifactsDir)bin\$(AssemblyName).Manifest.Task\$(Configuration)\netstandard2.0\$(AssemblyName).Manifest.Task.pdb" Condition="'$(DebugType)'!='embedded'"/>
</ItemGroup>

View File

@ -3,7 +3,7 @@
<metadata>
$CommonMetadataElements$
<dependencies>
<group targetFramework=".NETCoreApp3.0">
<group targetFramework=".NETCoreApp3.1">
<dependency id="Microsoft.Extensions.FileProviders.Abstractions" version="$version$" exclude="Build,Analyzers" />
</group>
<group targetFramework=".NETStandard2.0">
@ -14,9 +14,9 @@
<files>
$CommonFileElements$
<file src="$OutputBinary$" target="lib\" />
<file src="$OutputSymbol$" target="lib\" />
<file src="$OutputDocumentation$" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.dll" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.pdb" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.xml" target="lib\" />
<file src="build\**\*" target="build\" />
<file src="buildMultiTargeting\**\*" target="buildMultiTargeting\" />
<file src="$TaskAssemblyNetStandard$" target="tasks\netstandard2.0\$AssemblyName$.Manifest.Task.dll" />

View File

@ -3,7 +3,7 @@
<metadata>
$CommonMetadataElements$
<dependencies>
<group targetFramework=".NETCoreApp3.0">
<group targetFramework=".NETCoreApp3.1">
<dependency id="Microsoft.Extensions.FileProviders.Abstractions" version="$version$" exclude="Build,Analyzers" />
</group>
</dependencies>
@ -11,9 +11,9 @@
<files>
$CommonFileElements$
<file src="$OutputBinary$" target="lib\" />
<file src="$OutputSymbol$" target="lib\" />
<file src="$OutputDocumentation$" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.dll" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.pdb" target="lib\" />
<file src="$OutputPath$**\$AssemblyName$.xml" target="lib\" />
<file src="build\**\*" target="build\" />
<file src="buildMultiTargeting\**\*" target="buildMultiTargeting\" />
<file src="$TaskAssemblyNetStandard$" target="tasks\netstandard2.0\$AssemblyName$.Manifest.Task.dll" />

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
</PropertyGroup>
<ItemGroup>

View File

@ -1,14 +1,14 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netstandard2.0.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netcoreapp3.0.cs" />
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions.netcoreapp.cs" />
</ItemGroup>
</Project>

View File

@ -7,8 +7,8 @@ Commonly Used Types
Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck
</Description>
<RootNamespace>Microsoft.Extensions.Diagnostics.HealthChecks</RootNamespace>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>diagnostics;healthchecks</PackageTags>

View File

@ -1,7 +1,7 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.Extensions.Diagnostics.HealthChecks.netstandard2.0.cs" />
@ -9,8 +9,8 @@
<Reference Include="Microsoft.Extensions.Hosting.Abstractions" />
<Reference Include="Microsoft.Extensions.Options" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.Extensions.Diagnostics.HealthChecks.netcoreapp3.0.cs" />
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.Extensions.Diagnostics.HealthChecks.netcoreapp.cs" />
<Reference Include="Microsoft.Extensions.Diagnostics.HealthChecks.Abstractions" />
<Reference Include="Microsoft.Extensions.Hosting.Abstractions" />
<Reference Include="Microsoft.Extensions.Options" />

View File

@ -6,8 +6,8 @@ Commonly Used Types:
Microsoft.Extensions.Diagnostics.HealthChecks.HealthCheckService
Microsoft.Extensions.Diagnostics.HealthChecks.IHealthChecksBuilder
</Description>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>diagnostics;healthchecks</PackageTags>

View File

@ -3,7 +3,7 @@
<Import Project="$(RepoRoot)src\Logging\Logging.Testing\src\build\Microsoft.Extensions.Logging.Testing.props" />
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<RootNamespace>Microsoft.Extensions.Diagnostics.HealthChecks</RootNamespace>
</PropertyGroup>

View File

@ -1,14 +1,14 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.JSInterop.netstandard2.0.cs" />
<Reference Include="System.Text.Json" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.JSInterop.netcoreapp3.0.cs" />
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.JSInterop.netcoreapp.cs" />
</ItemGroup>
</Project>

View File

@ -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
{
/// <summary>
@ -15,6 +17,11 @@ namespace Microsoft.JSInterop
/// <returns>An instance of <see cref="DotNetObjectReference{TValue}" />.</returns>
public static DotNetObjectReference<TValue> Create<TValue>(TValue value) where TValue : class
{
if (value is null)
{
throw new ArgumentNullException(nameof(value));
}
return new DotNetObjectReference<TValue>(value);
}
}

View File

@ -24,6 +24,9 @@ namespace Microsoft.JSInterop.Infrastructure
private static readonly ConcurrentDictionary<AssemblyKey, IReadOnlyDictionary<string, (MethodInfo, Type[])>> _cachedMethodsByAssembly
= new ConcurrentDictionary<AssemblyKey, IReadOnlyDictionary<string, (MethodInfo, Type[])>>();
private static readonly ConcurrentDictionary<Type, IReadOnlyDictionary<string, (MethodInfo, Type[])>> _cachedMethodsByType
= new ConcurrentDictionary<Type, IReadOnlyDictionary<string, (MethodInfo, Type[])>>();
/// <summary>
/// Receives a call from JS to .NET, locating and invoking the specified method.
/// </summary>
@ -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<string, (MethodInfo, Type[])> ScanTypeForCallableMethods(Type type)
{
var result = new Dictionary<string, (MethodInfo, Type[])>(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<JSInvokableAttribute>(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<string, (MethodInfo, Type[])>(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<JSInvokableAttribute>(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;

View File

@ -1,8 +1,8 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<Description>Abstractions and features for interop between .NET and JavaScript code.</Description>
<PackageTags>javascript;interop</PackageTags>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

View File

@ -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<int>();
jsRuntime.Invoke<object>("_setup",
DotNetObjectReference.Create(targetInstance));
var argsJson = "[\"hello world\"]";
// Act
var resultJson = DotNetDispatcher.Invoke(jsRuntime, new DotNetInvocationInfo(null, nameof(GenericType<int>.EchoStringParameter), 1, default), argsJson);
// Assert
Assert.Equal("\"hello world\"", resultJson);
}
[Fact]
public void CanInvokeMethodsThatAcceptGenericParametersOnGenericTypes()
{
var jsRuntime = new TestJSRuntime();
var targetInstance = new GenericType<string>();
jsRuntime.Invoke<object>("_setup",
DotNetObjectReference.Create(targetInstance));
var argsJson = "[\"hello world\"]";
// Act
var resultJson = DotNetDispatcher.Invoke(jsRuntime, new DotNetInvocationInfo(null, nameof(GenericType<string>.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<ArgumentException>(() => 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<int>();
var jsRuntime = new TestJSRuntime();
jsRuntime.Invoke<object>("_setup",
DotNetObjectReference.Create(targetInstance));
var argsJson = "[\"hello world\"]";
// Act
var ex = Assert.Throws<ArgumentException>(() => 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<int>();
jsRuntime.Invoke<object>("_setup",
DotNetObjectReference.Create(targetInstance));
var argsJson = "[\"hello world\"]";
// Act & Assert
Assert.Throws<JsonException>(() =>
DotNetDispatcher.Invoke(jsRuntime, new DotNetInvocationInfo(null, nameof(GenericType<int>.EchoParameter), 1, default), argsJson));
}
[Fact]
public void CannotInvokeWithFewerNumberOfParameters()
{
@ -790,6 +861,18 @@ namespace Microsoft.JSInterop.Infrastructure
}
}
public class GenericType<TValue>
{
[JSInvokable] public string EchoStringParameter(string input) => input;
[JSInvokable] public TValue EchoParameter(TValue input) => input;
}
public class GenericMethodClass
{
[JSInvokable("StaticGenericMethod")] public static string StaticGenericMethod<TValue>(TValue input) => input.ToString();
[JSInvokable("InstanceGenericMethod")] public string GenericMethod<TValue>(TValue input) => input.ToString();
}
public class TestJSRuntime : JSInProcessRuntime
{
private TaskCompletionSource<object> _nextInvocationTcs = new TaskCompletionSource<object>();

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

View File

@ -0,0 +1,9 @@
<Project>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory)..\, Directory.Build.props))\Directory.Build.props" />
<PropertyGroup>
<!-- Override prerelease label even in the final build -->
<PreReleaseVersionLabel>$(BlazorWasmPreReleaseVersionLabel)</PreReleaseVersionLabel>
<DotNetFinalVersionKind />
</PropertyGroup>
</Project>

View File

@ -1,14 +1,14 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.Extensions.Localization.Abstractions.netstandard2.0.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.Extensions.Localization.Abstractions.netcoreapp3.0.cs" />
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.Extensions.Localization.Abstractions.netcoreapp.cs" />
</ItemGroup>
</Project>

View File

@ -6,8 +6,8 @@
Commonly used types:
Microsoft.Extensions.Localization.IStringLocalizer
Microsoft.Extensions.Localization.IStringLocalizer&lt;T&gt;</Description>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>localization</PackageTags>

View File

@ -1,7 +1,7 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.Extensions.Localization.netstandard2.0.cs" />
@ -10,8 +10,8 @@
<Reference Include="Microsoft.Extensions.Localization.Abstractions" />
<Reference Include="Microsoft.Extensions.Logging.Abstractions" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.Extensions.Localization.netcoreapp3.0.cs" />
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.Extensions.Localization.netcoreapp.cs" />
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<Reference Include="Microsoft.Extensions.Options" />
<Reference Include="Microsoft.Extensions.Localization.Abstractions" />

View File

@ -3,8 +3,8 @@
<PropertyGroup>
<Product>Microsoft .NET Extensions</Product>
<Description>Application localization services and default implementation based on ResourceManager to load localized assembly resources.</Description>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>localization</PackageTags>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
</PropertyGroup>
<ItemGroup>

View File

@ -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

View File

@ -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));

View File

@ -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;

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<OutputType>Exe</OutputType>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<OutputType>Exe</OutputType>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<OutputType>Exe</OutputType>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<OutputType>Exe</OutputType>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<OutputType>Exe</OutputType>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<OutputType>Exe</OutputType>
</PropertyGroup>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
</PropertyGroup>
</Project>

View File

@ -3,6 +3,39 @@
namespace Microsoft.AspNetCore.Testing
{
public partial class AspNetTestAssemblyRunner : Xunit.Sdk.XunitTestAssemblyRunner
{
public AspNetTestAssemblyRunner(Xunit.Abstractions.ITestAssembly testAssembly, System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases, Xunit.Abstractions.IMessageSink diagnosticMessageSink, Xunit.Abstractions.IMessageSink executionMessageSink, Xunit.Abstractions.ITestFrameworkExecutionOptions executionOptions) : base (default(Xunit.Abstractions.ITestAssembly), default(System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase>), default(Xunit.Abstractions.IMessageSink), default(Xunit.Abstractions.IMessageSink), default(Xunit.Abstractions.ITestFrameworkExecutionOptions)) { }
[System.Diagnostics.DebuggerStepThroughAttribute]
protected override System.Threading.Tasks.Task AfterTestAssemblyStartingAsync() { throw null; }
protected override System.Threading.Tasks.Task BeforeTestAssemblyFinishedAsync() { throw null; }
protected override System.Threading.Tasks.Task<Xunit.Sdk.RunSummary> RunTestCollectionAsync(Xunit.Sdk.IMessageBus messageBus, Xunit.Abstractions.ITestCollection testCollection, System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases, System.Threading.CancellationTokenSource cancellationTokenSource) { throw null; }
}
public partial class AspNetTestCollectionRunner : Xunit.Sdk.XunitTestCollectionRunner
{
public AspNetTestCollectionRunner(System.Collections.Generic.Dictionary<System.Type, object> assemblyFixtureMappings, Xunit.Abstractions.ITestCollection testCollection, System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases, Xunit.Abstractions.IMessageSink diagnosticMessageSink, Xunit.Sdk.IMessageBus messageBus, Xunit.Sdk.ITestCaseOrderer testCaseOrderer, Xunit.Sdk.ExceptionAggregator aggregator, System.Threading.CancellationTokenSource cancellationTokenSource) : base (default(Xunit.Abstractions.ITestCollection), default(System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase>), default(Xunit.Abstractions.IMessageSink), default(Xunit.Sdk.IMessageBus), default(Xunit.Sdk.ITestCaseOrderer), default(Xunit.Sdk.ExceptionAggregator), default(System.Threading.CancellationTokenSource)) { }
[System.Diagnostics.DebuggerStepThroughAttribute]
protected override System.Threading.Tasks.Task AfterTestCollectionStartingAsync() { throw null; }
protected override System.Threading.Tasks.Task BeforeTestCollectionFinishedAsync() { throw null; }
protected override System.Threading.Tasks.Task<Xunit.Sdk.RunSummary> RunTestClassAsync(Xunit.Abstractions.ITestClass testClass, Xunit.Abstractions.IReflectionTypeInfo @class, System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases) { throw null; }
}
public partial class AspNetTestFramework : Xunit.Sdk.XunitTestFramework
{
public AspNetTestFramework(Xunit.Abstractions.IMessageSink messageSink) : base (default(Xunit.Abstractions.IMessageSink)) { }
protected override Xunit.Abstractions.ITestFrameworkExecutor CreateExecutor(System.Reflection.AssemblyName assemblyName) { throw null; }
}
public partial class AspNetTestFrameworkExecutor : Xunit.Sdk.XunitTestFrameworkExecutor
{
public AspNetTestFrameworkExecutor(System.Reflection.AssemblyName assemblyName, Xunit.Abstractions.ISourceInformationProvider sourceInformationProvider, Xunit.Abstractions.IMessageSink diagnosticMessageSink) : base (default(System.Reflection.AssemblyName), default(Xunit.Abstractions.ISourceInformationProvider), default(Xunit.Abstractions.IMessageSink)) { }
[System.Diagnostics.DebuggerStepThroughAttribute]
protected override void RunTestCases(System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases, Xunit.Abstractions.IMessageSink executionMessageSink, Xunit.Abstractions.ITestFrameworkExecutionOptions executionOptions) { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple=true)]
public partial class AssemblyFixtureAttribute : System.Attribute
{
public AssemblyFixtureAttribute(System.Type fixtureType) { }
public System.Type FixtureType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple=false)]
[Xunit.Sdk.XunitTestCaseDiscovererAttribute("Microsoft.AspNetCore.Testing.ConditionalFactDiscoverer", "Microsoft.AspNetCore.Testing")]
public partial class ConditionalFactAttribute : Xunit.FactAttribute
@ -56,7 +89,7 @@ namespace Microsoft.AspNetCore.Testing
public static TException Throws<TException>(System.Func<object> testCode, string exceptionMessage) where TException : System.Exception { throw null; }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method)]
[Xunit.Sdk.TraitDiscovererAttribute("Microsoft.AspNetCore.Testing.FlakyTestDiscoverer", "Microsoft.AspNetCore.Testing")]
[Xunit.Sdk.TraitDiscovererAttribute("Microsoft.AspNetCore.Testing.FlakyTraitDiscoverer", "Microsoft.AspNetCore.Testing")]
public sealed partial class FlakyAttribute : System.Attribute, Xunit.Sdk.ITraitAttribute
{
public FlakyAttribute(string gitHubIssueUrl, string firstFilter, params string[] additionalFilters) { }
@ -88,9 +121,9 @@ namespace Microsoft.AspNetCore.Testing
public const string Windows10Amd64 = "Helix:Queue:Windows.10.Amd64.ClientRS4.VS2017.Open";
}
}
public partial class FlakyTestDiscoverer : Xunit.Sdk.ITraitDiscoverer
public partial class FlakyTraitDiscoverer : Xunit.Sdk.ITraitDiscoverer
{
public FlakyTestDiscoverer() { }
public FlakyTraitDiscoverer() { }
public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> GetTraits(Xunit.Abstractions.IAttributeInfo traitAttribute) { throw null; }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple=false)]
@ -131,6 +164,11 @@ namespace Microsoft.AspNetCore.Testing
bool IsMet { get; }
string SkipReason { get; }
}
public partial interface ITestMethodLifecycle
{
System.Threading.Tasks.Task OnTestEndAsync(Microsoft.AspNetCore.Testing.TestContext context, System.Exception exception, System.Threading.CancellationToken cancellationToken);
System.Threading.Tasks.Task OnTestStartAsync(Microsoft.AspNetCore.Testing.TestContext context, System.Threading.CancellationToken cancellationToken);
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public partial class MinimumOSVersionAttribute : System.Attribute, Microsoft.AspNetCore.Testing.ITestCondition
{
@ -152,6 +190,20 @@ namespace Microsoft.AspNetCore.Testing
public bool IsMet { get { throw null; } }
public string SkipReason { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=false)]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public partial class RepeatAttribute : System.Attribute
{
public RepeatAttribute(int runCount = 10) { }
public int RunCount { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
public partial class RepeatContext
{
public RepeatContext(int limit) { }
public static Microsoft.AspNetCore.Testing.RepeatContext Current { get { throw null; } }
public int CurrentIteration { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public int Limit { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Method)]
public partial class ReplaceCultureAttribute : Xunit.Sdk.BeforeAfterTestAttribute
{
@ -170,6 +222,11 @@ namespace Microsoft.AspNetCore.Testing
CLR = 2,
CoreCLR = 4,
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class, AllowMultiple=false)]
public partial class ShortClassNameAttribute : System.Attribute
{
public ShortClassNameAttribute() { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=false)]
public partial class SkipOnCIAttribute : System.Attribute, Microsoft.AspNetCore.Testing.ITestCondition
{
@ -210,10 +267,41 @@ namespace Microsoft.AspNetCore.Testing
[System.Diagnostics.DebuggerStepThroughAttribute]
public static System.Threading.Tasks.Task<T> TimeoutAfter<T>(this System.Threading.Tasks.Task<T> task, System.TimeSpan timeout, [System.Runtime.CompilerServices.CallerFilePathAttribute]string filePath = null, [System.Runtime.CompilerServices.CallerLineNumberAttribute]int lineNumber = 0) { throw null; }
}
public sealed partial class TestContext
{
public TestContext(System.Type testClass, object[] constructorArguments, System.Reflection.MethodInfo testMethod, object[] methodArguments, Xunit.Abstractions.ITestOutputHelper output) { }
public object[] ConstructorArguments { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public Microsoft.AspNetCore.Testing.TestFileOutputContext FileOutput { get { throw null; } }
public object[] MethodArguments { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public Xunit.Abstractions.ITestOutputHelper Output { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public System.Type TestClass { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public System.Reflection.MethodInfo TestMethod { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
public sealed partial class TestFileOutputContext
{
public TestFileOutputContext(Microsoft.AspNetCore.Testing.TestContext parent) { }
public string AssemblyOutputDirectory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string TestClassName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string TestClassOutputDirectory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string TestName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public static string GetAssemblyBaseDirectory(System.Reflection.Assembly assembly, string baseDirectory = null) { throw null; }
public static string GetOutputDirectory(System.Reflection.Assembly assembly) { throw null; }
public static string GetTestClassName(System.Type type) { throw null; }
public static string GetTestMethodName(System.Reflection.MethodInfo method, object[] arguments) { throw null; }
public string GetUniqueFileName(string prefix, string extension) { throw null; }
public static string RemoveIllegalFileChars(string s) { throw null; }
}
public static partial class TestMethodExtensions
{
public static string EvaluateSkipConditions(this Xunit.Abstractions.ITestMethod testMethod) { throw null; }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple=false, Inherited=true)]
public partial class TestOutputDirectoryAttribute : System.Attribute
{
public TestOutputDirectoryAttribute(string targetFramework, string baseDirectory = null) { }
public string BaseDirectory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string TargetFramework { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
[System.ObsoleteAttribute("This API is obsolete and the pattern its usage encouraged should not be used anymore. See https://github.com/aspnet/Extensions/issues/1697 for details.")]
public partial class TestPathUtilities
{
@ -231,6 +319,9 @@ namespace Microsoft.AspNetCore.Testing
public static partial class WindowsVersions
{
public const string Win10 = "10.0";
public const string Win10_19H2 = "10.0.18363";
public const string Win10_20H1 = "10.0.18990";
public const string Win10_RS4 = "10.0.17134";
public const string Win2008R2 = "6.1";
public const string Win7 = "6.1";
public const string Win8 = "6.2";

View File

@ -3,6 +3,39 @@
namespace Microsoft.AspNetCore.Testing
{
public partial class AspNetTestAssemblyRunner : Xunit.Sdk.XunitTestAssemblyRunner
{
public AspNetTestAssemblyRunner(Xunit.Abstractions.ITestAssembly testAssembly, System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases, Xunit.Abstractions.IMessageSink diagnosticMessageSink, Xunit.Abstractions.IMessageSink executionMessageSink, Xunit.Abstractions.ITestFrameworkExecutionOptions executionOptions) : base (default(Xunit.Abstractions.ITestAssembly), default(System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase>), default(Xunit.Abstractions.IMessageSink), default(Xunit.Abstractions.IMessageSink), default(Xunit.Abstractions.ITestFrameworkExecutionOptions)) { }
[System.Diagnostics.DebuggerStepThroughAttribute]
protected override System.Threading.Tasks.Task AfterTestAssemblyStartingAsync() { throw null; }
protected override System.Threading.Tasks.Task BeforeTestAssemblyFinishedAsync() { throw null; }
protected override System.Threading.Tasks.Task<Xunit.Sdk.RunSummary> RunTestCollectionAsync(Xunit.Sdk.IMessageBus messageBus, Xunit.Abstractions.ITestCollection testCollection, System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases, System.Threading.CancellationTokenSource cancellationTokenSource) { throw null; }
}
public partial class AspNetTestCollectionRunner : Xunit.Sdk.XunitTestCollectionRunner
{
public AspNetTestCollectionRunner(System.Collections.Generic.Dictionary<System.Type, object> assemblyFixtureMappings, Xunit.Abstractions.ITestCollection testCollection, System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases, Xunit.Abstractions.IMessageSink diagnosticMessageSink, Xunit.Sdk.IMessageBus messageBus, Xunit.Sdk.ITestCaseOrderer testCaseOrderer, Xunit.Sdk.ExceptionAggregator aggregator, System.Threading.CancellationTokenSource cancellationTokenSource) : base (default(Xunit.Abstractions.ITestCollection), default(System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase>), default(Xunit.Abstractions.IMessageSink), default(Xunit.Sdk.IMessageBus), default(Xunit.Sdk.ITestCaseOrderer), default(Xunit.Sdk.ExceptionAggregator), default(System.Threading.CancellationTokenSource)) { }
[System.Diagnostics.DebuggerStepThroughAttribute]
protected override System.Threading.Tasks.Task AfterTestCollectionStartingAsync() { throw null; }
protected override System.Threading.Tasks.Task BeforeTestCollectionFinishedAsync() { throw null; }
protected override System.Threading.Tasks.Task<Xunit.Sdk.RunSummary> RunTestClassAsync(Xunit.Abstractions.ITestClass testClass, Xunit.Abstractions.IReflectionTypeInfo @class, System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases) { throw null; }
}
public partial class AspNetTestFramework : Xunit.Sdk.XunitTestFramework
{
public AspNetTestFramework(Xunit.Abstractions.IMessageSink messageSink) : base (default(Xunit.Abstractions.IMessageSink)) { }
protected override Xunit.Abstractions.ITestFrameworkExecutor CreateExecutor(System.Reflection.AssemblyName assemblyName) { throw null; }
}
public partial class AspNetTestFrameworkExecutor : Xunit.Sdk.XunitTestFrameworkExecutor
{
public AspNetTestFrameworkExecutor(System.Reflection.AssemblyName assemblyName, Xunit.Abstractions.ISourceInformationProvider sourceInformationProvider, Xunit.Abstractions.IMessageSink diagnosticMessageSink) : base (default(System.Reflection.AssemblyName), default(Xunit.Abstractions.ISourceInformationProvider), default(Xunit.Abstractions.IMessageSink)) { }
[System.Diagnostics.DebuggerStepThroughAttribute]
protected override void RunTestCases(System.Collections.Generic.IEnumerable<Xunit.Sdk.IXunitTestCase> testCases, Xunit.Abstractions.IMessageSink executionMessageSink, Xunit.Abstractions.ITestFrameworkExecutionOptions executionOptions) { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple=true)]
public partial class AssemblyFixtureAttribute : System.Attribute
{
public AssemblyFixtureAttribute(System.Type fixtureType) { }
public System.Type FixtureType { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple=false)]
[Xunit.Sdk.XunitTestCaseDiscovererAttribute("Microsoft.AspNetCore.Testing.ConditionalFactDiscoverer", "Microsoft.AspNetCore.Testing")]
public partial class ConditionalFactAttribute : Xunit.FactAttribute
@ -56,7 +89,7 @@ namespace Microsoft.AspNetCore.Testing
public static TException Throws<TException>(System.Func<object> testCode, string exceptionMessage) where TException : System.Exception { throw null; }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method)]
[Xunit.Sdk.TraitDiscovererAttribute("Microsoft.AspNetCore.Testing.FlakyTestDiscoverer", "Microsoft.AspNetCore.Testing")]
[Xunit.Sdk.TraitDiscovererAttribute("Microsoft.AspNetCore.Testing.FlakyTraitDiscoverer", "Microsoft.AspNetCore.Testing")]
public sealed partial class FlakyAttribute : System.Attribute, Xunit.Sdk.ITraitAttribute
{
public FlakyAttribute(string gitHubIssueUrl, string firstFilter, params string[] additionalFilters) { }
@ -88,9 +121,9 @@ namespace Microsoft.AspNetCore.Testing
public const string Windows10Amd64 = "Helix:Queue:Windows.10.Amd64.ClientRS4.VS2017.Open";
}
}
public partial class FlakyTestDiscoverer : Xunit.Sdk.ITraitDiscoverer
public partial class FlakyTraitDiscoverer : Xunit.Sdk.ITraitDiscoverer
{
public FlakyTestDiscoverer() { }
public FlakyTraitDiscoverer() { }
public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> GetTraits(Xunit.Abstractions.IAttributeInfo traitAttribute) { throw null; }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Method, AllowMultiple=false)]
@ -131,6 +164,11 @@ namespace Microsoft.AspNetCore.Testing
bool IsMet { get; }
string SkipReason { get; }
}
public partial interface ITestMethodLifecycle
{
System.Threading.Tasks.Task OnTestEndAsync(Microsoft.AspNetCore.Testing.TestContext context, System.Exception exception, System.Threading.CancellationToken cancellationToken);
System.Threading.Tasks.Task OnTestStartAsync(Microsoft.AspNetCore.Testing.TestContext context, System.Threading.CancellationToken cancellationToken);
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=true)]
public partial class MinimumOSVersionAttribute : System.Attribute, Microsoft.AspNetCore.Testing.ITestCondition
{
@ -152,6 +190,20 @@ namespace Microsoft.AspNetCore.Testing
public bool IsMet { get { throw null; } }
public string SkipReason { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=false)]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
public partial class RepeatAttribute : System.Attribute
{
public RepeatAttribute(int runCount = 10) { }
public int RunCount { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
public partial class RepeatContext
{
public RepeatContext(int limit) { }
public static Microsoft.AspNetCore.Testing.RepeatContext Current { get { throw null; } }
public int CurrentIteration { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
public int Limit { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Method)]
public partial class ReplaceCultureAttribute : Xunit.Sdk.BeforeAfterTestAttribute
{
@ -170,6 +222,11 @@ namespace Microsoft.AspNetCore.Testing
CLR = 2,
CoreCLR = 4,
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly | System.AttributeTargets.Class, AllowMultiple=false)]
public partial class ShortClassNameAttribute : System.Attribute
{
public ShortClassNameAttribute() { }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=false)]
public partial class SkipOnCIAttribute : System.Attribute, Microsoft.AspNetCore.Testing.ITestCondition
{
@ -210,10 +267,41 @@ namespace Microsoft.AspNetCore.Testing
[System.Diagnostics.DebuggerStepThroughAttribute]
public static System.Threading.Tasks.Task<T> TimeoutAfter<T>(this System.Threading.Tasks.Task<T> task, System.TimeSpan timeout, [System.Runtime.CompilerServices.CallerFilePathAttribute]string filePath = null, [System.Runtime.CompilerServices.CallerLineNumberAttribute]int lineNumber = 0) { throw null; }
}
public sealed partial class TestContext
{
public TestContext(System.Type testClass, object[] constructorArguments, System.Reflection.MethodInfo testMethod, object[] methodArguments, Xunit.Abstractions.ITestOutputHelper output) { }
public object[] ConstructorArguments { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public Microsoft.AspNetCore.Testing.TestFileOutputContext FileOutput { get { throw null; } }
public object[] MethodArguments { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public Xunit.Abstractions.ITestOutputHelper Output { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public System.Type TestClass { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public System.Reflection.MethodInfo TestMethod { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
public sealed partial class TestFileOutputContext
{
public TestFileOutputContext(Microsoft.AspNetCore.Testing.TestContext parent) { }
public string AssemblyOutputDirectory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string TestClassName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string TestClassOutputDirectory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string TestName { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public static string GetAssemblyBaseDirectory(System.Reflection.Assembly assembly, string baseDirectory = null) { throw null; }
public static string GetOutputDirectory(System.Reflection.Assembly assembly) { throw null; }
public static string GetTestClassName(System.Type type) { throw null; }
public static string GetTestMethodName(System.Reflection.MethodInfo method, object[] arguments) { throw null; }
public string GetUniqueFileName(string prefix, string extension) { throw null; }
public static string RemoveIllegalFileChars(string s) { throw null; }
}
public static partial class TestMethodExtensions
{
public static string EvaluateSkipConditions(this Xunit.Abstractions.ITestMethod testMethod) { throw null; }
}
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly, AllowMultiple=false, Inherited=true)]
public partial class TestOutputDirectoryAttribute : System.Attribute
{
public TestOutputDirectoryAttribute(string targetFramework, string baseDirectory = null) { }
public string BaseDirectory { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
public string TargetFramework { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
}
[System.ObsoleteAttribute("This API is obsolete and the pattern its usage encouraged should not be used anymore. See https://github.com/aspnet/Extensions/issues/1697 for details.")]
public partial class TestPathUtilities
{
@ -231,6 +319,9 @@ namespace Microsoft.AspNetCore.Testing
public static partial class WindowsVersions
{
public const string Win10 = "10.0";
public const string Win10_19H2 = "10.0.18363";
public const string Win10_20H1 = "10.0.18990";
public const string Win10_RS4 = "10.0.17134";
public const string Win2008R2 = "6.1";
public const string Win7 = "6.1";
public const string Win8 = "6.2";

View File

@ -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
{
/// <summary>
/// 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.
/// </summary>
/// <remarks>
/// Requires defining <see cref="AspNetTestFramework"/> as the test framework.
/// </remarks>
public interface ITestMethodLifecycle
{
Task OnTestStartAsync(TestContext context, CancellationToken cancellationToken);
Task OnTestEndAsync(TestContext context, Exception exception, CancellationToken cancellationToken);
}
}

View File

@ -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
{
/// <summary>
/// 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.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)]
public class RepeatAttribute : Attribute
{
public RepeatAttribute(int runCount = 10)
{
RunCount = runCount;
}
/// <summary>
/// The number of times to run a test.
/// </summary>
public int RunCount { get; }
}
}

View File

@ -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<RepeatContext> _current = new AsyncLocal<RepeatContext>();
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; }
}
}

View File

@ -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
{
/// <summary>
/// Used to specify that <see cref="TestFileOutputContext.TestClassName"/> should used the
/// unqualified class name. This is needed when a fully-qualified class name exceeds
/// max path for logging.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = false)]
public class ShortClassNameAttribute : Attribute
{
}
}

View File

@ -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
{
/// <summary>
/// Provides access to contextual information about the running tests. Get access by
/// implementing <see cref="ITestMethodLifecycle"/>.
/// </summary>
/// <remarks>
/// Requires defining <see cref="AspNetTestFramework"/> as the test framework.
/// </remarks>
public sealed class TestContext
{
private Lazy<TestFileOutputContext> _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<TestFileOutputContext>(() => 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;
}
}

View File

@ -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
{
/// <summary>
/// Provides access to file storage for the running test. Get access by
/// implementing <see cref="ITestMethodLifecycle"/>, and accessing <see cref="TestContext.FileOutput"/>.
/// </summary>
/// <remarks>
/// Requires defining <see cref="AspNetTestFramework"/> as the test framework.
/// </remarks>
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<TestOutputDirectoryAttribute>().FirstOrDefault();
return attribute?.BaseDirectory;
}
public static string GetAssemblyBaseDirectory(Assembly assembly, string baseDirectory = null)
{
var attribute = assembly.GetCustomAttributes().OfType<TestOutputDirectoryAttribute>().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<ShortClassNameAttribute>() ??
type.Assembly.GetCustomAttribute<ShortClassNameAttribute>();
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();
}
}
}

View File

@ -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; }
}
}

View File

@ -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<Type, object> _assemblyFixtureMappings = new Dictionary<Type, object>();
public AspNetTestAssemblyRunner(
ITestAssembly testAssembly,
IEnumerable<IXunitTestCase> 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<AssemblyFixtureAttribute>()
.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<IDisposable>())
{
Aggregator.Run(disposable.Dispose);
}
return base.BeforeTestAssemblyFinishedAsync();
}
protected override Task<RunSummary> RunTestCollectionAsync(
IMessageBus messageBus,
ITestCollection testCollection,
IEnumerable<IXunitTestCase> testCases,
CancellationTokenSource cancellationTokenSource)
=> new AspNetTestCollectionRunner(
_assemblyFixtureMappings,
testCollection,
testCases,
DiagnosticMessageSink,
messageBus,
TestCaseOrderer,
new ExceptionAggregator(Aggregator),
cancellationTokenSource).RunAsync();
}
}

View File

@ -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<BeforeAfterTestAttribute> beforeAfterAttributes, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource)
{
return new AspNetTestRunner(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource);
}
}
}

View File

@ -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<IXunitTestCase> testCases,
IMessageSink diagnosticMessageSink,
IMessageBus messageBus,
ITestCaseOrderer testCaseOrderer,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource,
IDictionary<Type, object> collectionFixtureMappings)
: base(testClass, @class, testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource, collectionFixtureMappings)
{
}
protected override Task<RunSummary> RunTestMethodAsync(ITestMethod testMethod, IReflectionMethodInfo method, IEnumerable<IXunitTestCase> testCases, object[] constructorArguments)
{
var runner = new AspNetTestMethodRunner(
testMethod,
Class,
method,
testCases,
DiagnosticMessageSink,
MessageBus,
new ExceptionAggregator(Aggregator),
CancellationTokenSource,
constructorArguments);
return runner.RunAsync();
}
}
}

View File

@ -0,0 +1,75 @@
// 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<Type, object> _assemblyFixtureMappings;
private readonly IMessageSink _diagnosticMessageSink;
public AspNetTestCollectionRunner(
Dictionary<Type, object> assemblyFixtureMappings,
ITestCollection testCollection,
IEnumerable<IXunitTestCase> 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<RunSummary> RunTestClassAsync(ITestClass testClass, IReflectionTypeInfo @class, IEnumerable<IXunitTestCase> testCases)
{
var runner = new AspNetTestClassRunner(
testClass,
@class,
testCases,
DiagnosticMessageSink,
MessageBus,
TestCaseOrderer,
new ExceptionAggregator(Aggregator),
CancellationTokenSource,
CollectionFixtureMappings);
return runner.RunAsync();
}
}
}

View File

@ -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);
}
}

View File

@ -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<IXunitTestCase> testCases, IMessageSink executionMessageSink, ITestFrameworkExecutionOptions executionOptions)
{
using (var assemblyRunner = new AspNetTestAssemblyRunner(TestAssembly, testCases, DiagnosticMessageSink, executionMessageSink, executionOptions))
{
await assemblyRunner.RunAsync();
}
}
}
}

View File

@ -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<BeforeAfterTestAttribute> beforeAfterAttributes,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource)
: base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, beforeAfterAttributes, aggregator, cancellationTokenSource)
{
}
protected override async Task<decimal> 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<ITestMethodLifecycle> GetLifecycleHooks(object testClassInstance, Type testClass, MethodInfo testMethod)
{
foreach (var attribute in testMethod.GetCustomAttributes(inherit: true).OfType<ITestMethodLifecycle>())
{
yield return attribute;
}
if (testClassInstance is ITestMethodLifecycle instance)
{
yield return instance;
}
foreach (var attribute in testClass.GetCustomAttributes(inherit: true).OfType<ITestMethodLifecycle>())
{
yield return attribute;
}
foreach (var attribute in testClass.Assembly.GetCustomAttributes(inherit: true).OfType<ITestMethodLifecycle>())
{
yield return attribute;
}
}
}
}

View File

@ -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<IXunitTestCase> 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<RunSummary> 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);
}
}
}

View File

@ -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<BeforeAfterTestAttribute> beforeAfterAttributes,
ExceptionAggregator aggregator,
CancellationTokenSource cancellationTokenSource)
: base(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource)
{
}
protected override async Task<decimal> 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<decimal> 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<RepeatAttribute>();
if (attributeCandidate != null)
{
return attributeCandidate;
}
attributeCandidate = methodInfo.DeclaringType.GetCustomAttribute<RepeatAttribute>();
if (attributeCandidate != null)
{
return attributeCandidate;
}
return methodInfo.DeclaringType.Assembly.GetCustomAttribute<RepeatAttribute>();
}
}
}

View File

@ -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<BeforeAfterTestAttribute> beforeAfterAttributes, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource)
{
return new AspNetTestRunner(test, messageBus, testClass, constructorArguments, testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource);
}
}
}

View File

@ -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; }
}
}

View File

@ -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<IXunitTestCase> 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);
}
}
}

View File

@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Testing
/// to <c>xunit.console.exe</c>. Similarly, it can run only flaky tests using <c>-trait "Flaky:AzP:OS:all=true" -trait "Flaky:AzP:OS:Darwin=true"</c>
/// </para>
/// </example>
[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
{

View File

@ -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<KeyValuePair<string, string>> GetTraits(IAttributeInfo traitAttribute)
{

View File

@ -3,7 +3,6 @@
using System;
using System.Runtime.InteropServices;
using Microsoft.Win32;
namespace Microsoft.AspNetCore.Testing
{
@ -14,49 +13,36 @@ namespace Microsoft.AspNetCore.Testing
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Assembly, AllowMultiple = true)]
public class MinimumOSVersionAttribute : Attribute, ITestCondition
{
private readonly OperatingSystems _excludedOperatingSystem;
private readonly OperatingSystems _targetOS;
private readonly Version _minVersion;
private readonly OperatingSystems _osPlatform;
private readonly Version _osVersion;
private readonly OperatingSystems _currentOS;
private readonly Version _currentVersion;
private readonly bool _skip;
public MinimumOSVersionAttribute(OperatingSystems operatingSystem, string minVersion) :
this(
operatingSystem,
GetCurrentOS(),
GetCurrentOSVersion(),
Version.Parse(minVersion))
this(operatingSystem, Version.Parse(minVersion), GetCurrentOS(), GetCurrentOSVersion())
{
}
// to enable unit testing
internal MinimumOSVersionAttribute(
OperatingSystems operatingSystem, OperatingSystems osPlatform, Version osVersion, Version minVersion)
internal MinimumOSVersionAttribute(OperatingSystems targetOS, Version minVersion, OperatingSystems currentOS, Version currentVersion)
{
if (operatingSystem != OperatingSystems.Windows)
if (targetOS != OperatingSystems.Windows)
{
throw new NotImplementedException("Min version support is only implemented for Windows.");
}
_excludedOperatingSystem = operatingSystem;
_targetOS = targetOS;
_minVersion = minVersion;
_osPlatform = osPlatform;
_osVersion = osVersion;
_currentOS = currentOS;
_currentVersion = currentVersion;
SkipReason = $"This test requires {_excludedOperatingSystem} {_minVersion} or later.";
// Do not skip other OS's, Use OSSkipConditionAttribute or a separate MinimumOSVersionAttribute for that.
_skip = _targetOS == _currentOS && _minVersion > _currentVersion;
SkipReason = $"This test requires {_targetOS} {_minVersion} or later.";
}
public bool IsMet
{
get
{
// Do not skip other OS's, Use OSSkipConditionAttribute or a separate MinimumOSVersionAttribute for that.
if (_osPlatform != _excludedOperatingSystem)
{
return true;
}
return _osVersion >= _minVersion;
}
}
// Since a test would be executed only if 'IsMet' is true, return false if we want to skip
public bool IsMet => !_skip;
public string SkipReason { get; set; }
@ -77,34 +63,16 @@ namespace Microsoft.AspNetCore.Testing
throw new PlatformNotSupportedException();
}
private static Version GetCurrentOSVersion()
static private Version GetCurrentOSVersion()
{
// currently not used on other OS's
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// Win10+
var key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
var major = key.GetValue("CurrentMajorVersionNumber") as int?;
var minor = key.GetValue("CurrentMinorVersionNumber") as int?;
if (major.HasValue && minor.HasValue)
{
return new Version(major.Value, minor.Value);
}
// CurrentVersion doesn't work past Win8.1
var current = key.GetValue("CurrentVersion") as string;
if (!string.IsNullOrEmpty(current) && Version.TryParse(current, out var currentVersion))
{
return currentVersion;
}
// Environment.OSVersion doesn't work past Win8.
return Environment.OSVersion.Version;
}
else
{
return new Version();
// Not implemented, but this will still be called before the OS check happens so don't throw.
return new Version(0, 0);
}
}
}

View File

@ -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<string>(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)

View File

@ -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;
/// <summary/>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
public WORKAROUND_SkippedDataRowTestCase() { }
/// <summary>
/// Initializes a new instance of the <see cref="XunitSkippedDataRowTestCase"/> class.
/// </summary>
/// <param name="diagnosticMessageSink">The message sink used to send diagnostic messages</param>
/// <param name="defaultMethodDisplay">Default method display to use (when not customized).</param>
/// <param name="testMethod">The test method this test case belongs to.</param>
/// <param name="skipReason">The reason that this test case will be skipped</param>
/// <param name="testMethodArguments">The arguments for the test method.</param>
[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) { }
/// <summary>
/// Initializes a new instance of the <see cref="XunitSkippedDataRowTestCase"/> class.
/// </summary>
/// <param name="diagnosticMessageSink">The message sink used to send diagnostic messages</param>
/// <param name="defaultMethodDisplay">Default method display to use (when not customized).</param>
/// <param name="defaultMethodDisplayOptions">Default method display options to use (when not customized).</param>
/// <param name="testMethod">The test method this test case belongs to.</param>
/// <param name="skipReason">The reason that this test case will be skipped</param>
/// <param name="testMethodArguments">The arguments for the test method.</param>
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;
}
/// <inheritdoc/>
public override void Deserialize(IXunitSerializationInfo data)
{
// SkipReason has to be read before we call base.Deserialize, this is the workaround.
this.skipReason = data.GetValue<string>("SkipReason");
base.Deserialize(data);
}
/// <inheritdoc/>
protected override string GetSkipReason(IAttributeInfo factAttribute)
{
return skipReason;
}
/// <inheritdoc/>
public override void Serialize(IXunitSerializationInfo data)
{
base.Serialize(data);
data.AddValue("SkipReason", skipReason);
}
}
}

View File

@ -3,6 +3,9 @@
namespace Microsoft.AspNetCore.Testing
{
/// <summary>
/// https://en.wikipedia.org/wiki/Windows_10_version_history
/// </summary>
public static class WindowsVersions
{
public const string Win7 = "6.1";
@ -14,5 +17,20 @@ namespace Microsoft.AspNetCore.Testing
public const string Win81 = "6.3";
public const string Win10 = "10.0";
/// <summary>
/// 1803, RS4, 17134
/// </summary>
public const string Win10_RS4 = "10.0.17134";
/// <summary>
/// 1909, 19H2, 18363
/// </summary>
public const string Win10_19H2 = "10.0.18363";
/// <summary>
/// _, 20H2, 18990
/// </summary>
public const string Win10_20H1 = "10.0.18990";
}
}

View File

@ -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<TestCollectionFixture>
{
}
}

View File

@ -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()

View File

@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Testing
Assert.True(true);
}
#if NETCOREAPP3_0
#if NETCOREAPP
[ConditionalTheory]
[FrameworkSkipCondition(RuntimeFrameworks.CLR)]
[MemberData(nameof(GetInts))]

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
<!-- allow skipped tests -->
<NoWarn>$(NoWarn);xUnit1004</NoWarn>

View File

@ -0,0 +1,77 @@
// 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 Xunit;
namespace Microsoft.AspNetCore.Testing
{
public class MinimumOSVersionAttributeTest
{
[Fact]
public void Linux_ThrowsNotImplemeneted()
{
Assert.Throws<NotImplementedException>(() => new MinimumOSVersionAttribute(OperatingSystems.Linux, "2.5"));
}
[Fact]
public void Mac_ThrowsNotImplemeneted()
{
Assert.Throws<NotImplementedException>(() => new MinimumOSVersionAttribute(OperatingSystems.MacOSX, "2.5"));
}
[Fact]
public void WindowsOrLinux_ThrowsNotImplemeneted()
{
Assert.Throws<NotImplementedException>(() => new MinimumOSVersionAttribute(OperatingSystems.Linux | OperatingSystems.Windows, "2.5"));
}
[Fact]
public void DoesNotSkip_LaterVersions()
{
var osSkipAttribute = new MinimumOSVersionAttribute(
OperatingSystems.Windows,
new Version("2.0"),
OperatingSystems.Windows,
new Version("2.5"));
Assert.True(osSkipAttribute.IsMet);
}
[Fact]
public void DoesNotSkip_SameVersion()
{
var osSkipAttribute = new MinimumOSVersionAttribute(
OperatingSystems.Windows,
new Version("2.5"),
OperatingSystems.Windows,
new Version("2.5"));
Assert.True(osSkipAttribute.IsMet);
}
[Fact]
public void Skip_EarlierVersion()
{
var osSkipAttribute = new MinimumOSVersionAttribute(
OperatingSystems.Windows,
new Version("3.0"),
OperatingSystems.Windows,
new Version("2.5"));
Assert.False(osSkipAttribute.IsMet);
}
[Fact]
public void DoesNotSkip_WhenOnlyVersionsMatch()
{
var osSkipAttribute = new MinimumOSVersionAttribute(
OperatingSystems.Windows,
new Version("2.5"),
OperatingSystems.Linux,
new Version("2.5"));
Assert.True(osSkipAttribute.IsMet);
}
}
}

View File

@ -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;
using System.Runtime.InteropServices;
using Microsoft.Win32;
using Xunit;
namespace Microsoft.AspNetCore.Testing
{
public class MinimumOSVersionTest
{
[ConditionalFact]
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8)]
public void RunTest_Win8DoesNotRunOnWin7()
{
Assert.False(
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
Environment.OSVersion.Version.ToString().StartsWith("6.1"),
"Test should not be running on Win7 or Win2008R2.");
}
[ConditionalTheory]
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8)]
[InlineData(1)]
public void RunTheory_Win8DoesNotRunOnWin7(int arg)
{
Assert.False(
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
Environment.OSVersion.Version.ToString().StartsWith("6.1"),
"Test should not be running on Win7 or Win2008R2.");
}
[ConditionalFact]
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_RS4)]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
public void RunTest_Win10_RS4()
{
Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
var versionKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
Assert.NotNull(versionKey);
var currentVersion = (string)versionKey.GetValue("CurrentBuildNumber");
Assert.NotNull(currentVersion);
Assert.True(17134 <= int.Parse(currentVersion));
}
[ConditionalFact]
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win10_19H2)]
[OSSkipCondition(OperatingSystems.Linux | OperatingSystems.MacOSX)]
public void RunTest_Win10_19H2()
{
Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
var versionKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion");
Assert.NotNull(versionKey);
var currentVersion = (string)versionKey.GetValue("CurrentBuildNumber");
Assert.NotNull(currentVersion);
Assert.True(18363 <= int.Parse(currentVersion));
}
}
[MinimumOSVersion(OperatingSystems.Windows, WindowsVersions.Win8)]
public class OSMinVersionClassTest
{
[ConditionalFact]
public void TestSkipClass_Win8DoesNotRunOnWin7()
{
Assert.False(
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
Environment.OSVersion.Version.ToString().StartsWith("6.1"),
"Test should not be running on Win7 or Win2008R2.");
}
}
}

View File

@ -0,0 +1,6 @@
using Microsoft.AspNetCore.Testing;
using Xunit;
[assembly: Repeat(1)]
[assembly: AssemblyFixture(typeof(TestAssemblyFixture))]
[assembly: TestFramework("Microsoft.AspNetCore.Testing.AspNetTestFramework", "Microsoft.AspNetCore.Testing")]

View File

@ -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);
}
}
}

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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;
}
}
}

View File

@ -1,7 +1,7 @@
<!-- This file is automatically generated. -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft.Extensions.WebEncoders.netstandard2.0.cs" />
@ -9,8 +9,8 @@
<Reference Include="Microsoft.Extensions.Options" />
<Reference Include="System.Text.Encodings.Web" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.0'">
<Compile Include="Microsoft.Extensions.WebEncoders.netcoreapp3.0.cs" />
<ItemGroup Condition="'$(TargetFramework)' == '$(DefaultNetCoreTargetFramework)'">
<Compile Include="Microsoft.Extensions.WebEncoders.netcoreapp.cs" />
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
<Reference Include="Microsoft.Extensions.Options" />
</ItemGroup>

View File

@ -2,8 +2,8 @@
<PropertyGroup>
<Description>Contains registration and configuration APIs to add the core framework encoders to a dependency injection container.</Description>
<TargetFrameworks>netstandard2.0;netcoreapp3.0</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">netcoreapp3.0</TargetFrameworks>
<TargetFrameworks>netstandard2.0;$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<TargetFrameworks Condition="'$(DotNetBuildFromSource)' == 'true'">$(DefaultNetCoreTargetFramework)</TargetFrameworks>
<NoWarn>$(NoWarn);CS1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageTags>aspnetcore</PackageTags>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp3.0;net472</TargetFrameworks>
<TargetFrameworks>$(DefaultNetCoreTargetFramework);net472</TargetFrameworks>
</PropertyGroup>
<ItemGroup>