Update headless xUnit support to v3 (#20481)
* Update headless xUnit support to v3 * Update API suppressions
This commit is contained in:
committed by
GitHub
parent
1086d9b5b0
commit
ff0a61486d
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- https://learn.microsoft.com/dotnet/fundamentals/package-validation/diagnostic-ids -->
|
||||
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Avalonia.Headless.XUnit.AvaloniaTestFrameworkTypeDiscoverer</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Avalonia.Headless.XUnit.AvaloniaUIFactDiscoverer</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Avalonia.Headless.XUnit.AvaloniaTestFrameworkTypeDiscoverer</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0001</DiagnosticId>
|
||||
<Target>T:Avalonia.Headless.XUnit.AvaloniaUIFactDiscoverer</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Avalonia.Headless.XUnit.AvaloniaFactAttribute.#ctor</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer.#ctor(Xunit.Abstractions.IMessageSink)</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Avalonia.Headless.XUnit.AvaloniaFactAttribute.#ctor</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer.#ctor(Xunit.Abstractions.IMessageSink)</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0007</DiagnosticId>
|
||||
<Target>T:Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0007</DiagnosticId>
|
||||
<Target>T:Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0008</DiagnosticId>
|
||||
<Target>T:Avalonia.Headless.XUnit.AvaloniaTestFrameworkAttribute</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net10.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0008</DiagnosticId>
|
||||
<Target>T:Avalonia.Headless.XUnit.AvaloniaTestFrameworkAttribute</Target>
|
||||
<Left>baseline/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Left>
|
||||
<Right>current/Avalonia.Headless.XUnit/lib/net8.0/Avalonia.Headless.XUnit.dll</Right>
|
||||
</Suppression>
|
||||
</Suppressions>
|
||||
+4
-5
@@ -1,14 +1,13 @@
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Condition="'$(IsXUnit2)'!='true'">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit.v3.mtp-v2" Version="3.2.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup Condition="'$(IsXUnit2)'=='true'">
|
||||
<PackageReference Include="xunit" Version="2.9.3" />
|
||||
<PackageReference Include="YTest.MTP.XUnit2" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
|
||||
<SignAssembly>False</SignAssembly>
|
||||
<NoWarn>$(NoWarn);CS8002</NoWarn> <!-- ignore signing warnings for unit tests -->
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<!-- Use lower minor version, as it is supposed to be compatible -->
|
||||
<PackageReference Include="xunit.core" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.v3.extensibility.core" Version="3.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Threading;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal sealed class AvaloniaDelayEnumeratedTheoryTestCase
|
||||
: XunitDelayEnumeratedTheoryTestCase, ISelfExecutingXunitTestCase
|
||||
{
|
||||
public AvaloniaDelayEnumeratedTheoryTestCase(
|
||||
IXunitTestMethod testMethod,
|
||||
string testCaseDisplayName,
|
||||
string uniqueID,
|
||||
bool @explicit,
|
||||
bool skipTestWithoutData,
|
||||
Type[]? skipExceptions = null,
|
||||
string? skipReason = null,
|
||||
Type? skipType = null,
|
||||
string? skipUnless = null,
|
||||
string? skipWhen = null,
|
||||
Dictionary<string, HashSet<string>>? traits = null,
|
||||
string? sourceFilePath = null,
|
||||
int? sourceLineNumber = null,
|
||||
int? timeout = null)
|
||||
: base(
|
||||
testMethod,
|
||||
testCaseDisplayName,
|
||||
uniqueID,
|
||||
@explicit,
|
||||
skipTestWithoutData,
|
||||
skipExceptions,
|
||||
skipReason,
|
||||
skipType,
|
||||
skipUnless,
|
||||
skipWhen,
|
||||
traits,
|
||||
sourceFilePath,
|
||||
sourceLineNumber,
|
||||
timeout)
|
||||
{
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
|
||||
public AvaloniaDelayEnumeratedTheoryTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
public async ValueTask<RunSummary> Run(
|
||||
ExplicitOption explicitOption,
|
||||
IMessageBus messageBus,
|
||||
object?[] constructorArguments,
|
||||
ExceptionAggregator aggregator,
|
||||
CancellationTokenSource cancellationTokenSource)
|
||||
{
|
||||
var tests = await aggregator.RunAsync(CreateTests, []);
|
||||
|
||||
// We need to block the XUnit thread to ensure its concurrency throttle is effective.
|
||||
// See https://github.com/AArnott/Xunit.StaFact/pull/55#issuecomment-826187354 for details.
|
||||
var runSummary = Task.Run(async () => await AvaloniaTestCaseRunner.Instance.Run(
|
||||
this,
|
||||
tests,
|
||||
messageBus,
|
||||
aggregator,
|
||||
cancellationTokenSource,
|
||||
TestCaseDisplayName,
|
||||
SkipReason,
|
||||
explicitOption,
|
||||
constructorArguments))
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
|
||||
return runSummary;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
@@ -12,24 +10,8 @@ namespace Avalonia.Headless.XUnit;
|
||||
/// such that awaited expressions resume on the test's "main thread".
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
[XunitTestCaseDiscoverer("Avalonia.Headless.XUnit.AvaloniaUIFactDiscoverer", "Avalonia.Headless.XUnit")]
|
||||
public sealed class AvaloniaFactAttribute : FactAttribute
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class AvaloniaUIFactDiscoverer : FactDiscoverer
|
||||
{
|
||||
private readonly IMessageSink diagnosticMessageSink;
|
||||
public AvaloniaUIFactDiscoverer(IMessageSink diagnosticMessageSink)
|
||||
: base(diagnosticMessageSink)
|
||||
{
|
||||
this.diagnosticMessageSink = diagnosticMessageSink;
|
||||
}
|
||||
|
||||
protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
|
||||
{
|
||||
return new AvaloniaTestCase(diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod);
|
||||
}
|
||||
}
|
||||
[XunitTestCaseDiscoverer(typeof(AvaloniaFactDiscoverer))]
|
||||
public sealed class AvaloniaFactAttribute(
|
||||
[CallerFilePath] string? sourceFilePath = null,
|
||||
[CallerLineNumber] int sourceLineNumber = -1)
|
||||
: FactAttribute(sourceFilePath, sourceLineNumber);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Xunit.Internal;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class AvaloniaFactDiscoverer : FactDiscoverer
|
||||
{
|
||||
protected override IXunitTestCase CreateTestCase(
|
||||
ITestFrameworkDiscoveryOptions discoveryOptions,
|
||||
IXunitTestMethod testMethod,
|
||||
IFactAttribute factAttribute)
|
||||
{
|
||||
var details = TestIntrospectionHelper.GetTestCaseDetails(discoveryOptions, testMethod, factAttribute);
|
||||
|
||||
return new AvaloniaTestCase(
|
||||
details.ResolvedTestMethod,
|
||||
details.TestCaseDisplayName,
|
||||
details.UniqueID,
|
||||
details.Explicit,
|
||||
details.SkipExceptions,
|
||||
details.SkipReason,
|
||||
details.SkipType,
|
||||
details.SkipUnless,
|
||||
details.SkipWhen,
|
||||
testMethod.Traits.ToReadWrite(StringComparer.OrdinalIgnoreCase),
|
||||
sourceFilePath: details.SourceFilePath,
|
||||
sourceLineNumber: details.SourceLineNumber,
|
||||
timeout: details.Timeout);
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Threading;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal class AvaloniaTestAssemblyRunner : XunitTestAssemblyRunner
|
||||
{
|
||||
private HeadlessUnitTestSession? _session;
|
||||
|
||||
public AvaloniaTestAssemblyRunner(ITestAssembly testAssembly, IEnumerable<IXunitTestCase> testCases,
|
||||
IMessageSink diagnosticMessageSink, IMessageSink executionMessageSink,
|
||||
ITestFrameworkExecutionOptions executionOptions) : base(testAssembly, testCases, diagnosticMessageSink,
|
||||
executionMessageSink, executionOptions)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void SetupSyncContext(int maxParallelThreads)
|
||||
{
|
||||
_session = HeadlessUnitTestSession.GetOrStartForAssembly(
|
||||
Assembly.Load(new AssemblyName(TestAssembly.Assembly.Name)));
|
||||
base.SetupSyncContext(1);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_session?.Dispose();
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
protected override Task<RunSummary> RunTestCollectionAsync(
|
||||
IMessageBus messageBus,
|
||||
ITestCollection testCollection,
|
||||
IEnumerable<IXunitTestCase> testCases,
|
||||
CancellationTokenSource cancellationTokenSource)
|
||||
{
|
||||
return new AvaloniaTestCollectionRunner(_session!, testCollection, testCases, DiagnosticMessageSink, messageBus,
|
||||
TestCaseOrderer, new ExceptionAggregator(Aggregator), cancellationTokenSource).RunAsync();
|
||||
}
|
||||
|
||||
private class AvaloniaTestCollectionRunner : XunitTestCollectionRunner
|
||||
{
|
||||
private readonly HeadlessUnitTestSession _session;
|
||||
|
||||
public AvaloniaTestCollectionRunner(HeadlessUnitTestSession session,
|
||||
ITestCollection testCollection, IEnumerable<IXunitTestCase> testCases,
|
||||
IMessageSink diagnosticMessageSink, IMessageBus messageBus, ITestCaseOrderer testCaseOrderer,
|
||||
ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource) : base(testCollection,
|
||||
testCases, diagnosticMessageSink, messageBus, testCaseOrderer, aggregator, cancellationTokenSource)
|
||||
{
|
||||
_session = session;
|
||||
}
|
||||
|
||||
protected override Task<RunSummary> RunTestClassAsync(
|
||||
ITestClass testClass,
|
||||
IReflectionTypeInfo @class,
|
||||
IEnumerable<IXunitTestCase> testCases)
|
||||
{
|
||||
return new AvaloniaTestClassRunner(_session, testClass, @class, testCases, DiagnosticMessageSink, MessageBus,
|
||||
TestCaseOrderer, new ExceptionAggregator(Aggregator), CancellationTokenSource,
|
||||
CollectionFixtureMappings).RunAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private class AvaloniaTestClassRunner : XunitTestClassRunner
|
||||
{
|
||||
private readonly HeadlessUnitTestSession _session;
|
||||
|
||||
public AvaloniaTestClassRunner(HeadlessUnitTestSession session, 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)
|
||||
{
|
||||
_session = session;
|
||||
}
|
||||
|
||||
protected override Task<RunSummary> RunTestMethodAsync(
|
||||
ITestMethod testMethod,
|
||||
IReflectionMethodInfo method,
|
||||
IEnumerable<IXunitTestCase> testCases,
|
||||
object[] constructorArguments)
|
||||
{
|
||||
return new AvaloniaTestMethodRunner(_session, testMethod, Class, method, testCases, DiagnosticMessageSink,
|
||||
MessageBus, new ExceptionAggregator(Aggregator), CancellationTokenSource,
|
||||
constructorArguments).RunAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private class AvaloniaTestMethodRunner : XunitTestMethodRunner
|
||||
{
|
||||
private readonly HeadlessUnitTestSession _session;
|
||||
private readonly IMessageBus _messageBus;
|
||||
private readonly ExceptionAggregator _aggregator;
|
||||
private readonly CancellationTokenSource _cancellationTokenSource;
|
||||
private readonly object[] _constructorArguments;
|
||||
|
||||
public AvaloniaTestMethodRunner(HeadlessUnitTestSession session, 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)
|
||||
{
|
||||
_session = session;
|
||||
_messageBus = messageBus;
|
||||
_aggregator = aggregator;
|
||||
_cancellationTokenSource = cancellationTokenSource;
|
||||
_constructorArguments = constructorArguments;
|
||||
}
|
||||
|
||||
protected override Task<RunSummary> RunTestCaseAsync(IXunitTestCase testCase)
|
||||
{
|
||||
return AvaloniaTestCaseRunner.RunTest(_session, testCase, testCase.DisplayName, testCase.SkipReason,
|
||||
_constructorArguments, testCase.TestMethodArguments, _messageBus, _aggregator,
|
||||
_cancellationTokenSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,46 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit.Abstractions;
|
||||
using Avalonia.Threading;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal class AvaloniaTestCase : XunitTestCase
|
||||
internal sealed class AvaloniaTestCase : XunitTestCase, ISelfExecutingXunitTestCase
|
||||
{
|
||||
public AvaloniaTestCase(
|
||||
IMessageSink diagnosticMessageSink,
|
||||
TestMethodDisplay defaultMethodDisplay,
|
||||
ITestMethod testMethod,
|
||||
object?[]? testMethodArguments = null)
|
||||
: base(diagnosticMessageSink, defaultMethodDisplay, TestMethodDisplayOptions.None, testMethod, testMethodArguments)
|
||||
IXunitTestMethod testMethod,
|
||||
string testCaseDisplayName,
|
||||
string uniqueID,
|
||||
bool @explicit,
|
||||
Type[]? skipExceptions = null,
|
||||
string? skipReason = null,
|
||||
Type? skipType = null,
|
||||
string? skipUnless = null,
|
||||
string? skipWhen = null,
|
||||
Dictionary<string, HashSet<string>>? traits = null,
|
||||
object?[]? testMethodArguments = null,
|
||||
string? sourceFilePath = null,
|
||||
int? sourceLineNumber = null,
|
||||
int? timeout = null)
|
||||
: base(
|
||||
testMethod,
|
||||
testCaseDisplayName,
|
||||
uniqueID,
|
||||
@explicit,
|
||||
skipExceptions,
|
||||
skipReason,
|
||||
skipType,
|
||||
skipUnless,
|
||||
skipWhen,
|
||||
traits,
|
||||
testMethodArguments,
|
||||
sourceFilePath,
|
||||
sourceLineNumber,
|
||||
timeout)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -24,23 +50,30 @@ internal class AvaloniaTestCase : XunitTestCase
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<RunSummary> RunAsync(
|
||||
IMessageSink diagnosticMessageSink,
|
||||
public async ValueTask<RunSummary> Run(
|
||||
ExplicitOption explicitOption,
|
||||
IMessageBus messageBus,
|
||||
object[] constructorArguments,
|
||||
object?[] constructorArguments,
|
||||
ExceptionAggregator aggregator,
|
||||
CancellationTokenSource cancellationTokenSource)
|
||||
{
|
||||
var session = HeadlessUnitTestSession.GetOrStartForAssembly(Method.ToRuntimeMethod().DeclaringType?.Assembly);
|
||||
var tests = await aggregator.RunAsync(CreateTests, []);
|
||||
|
||||
// We need to block the XUnit thread to ensure its concurrency throttle is effective.
|
||||
// See https://github.com/AArnott/Xunit.StaFact/pull/55#issuecomment-826187354 for details.
|
||||
var runSummary =
|
||||
Task.Run(() => AvaloniaTestCaseRunner.RunTest(session, this, DisplayName, SkipReason, constructorArguments,
|
||||
TestMethodArguments, messageBus, aggregator, cancellationTokenSource))
|
||||
var runSummary = Task.Run(async () => await AvaloniaTestCaseRunner.Instance.Run(
|
||||
this,
|
||||
tests,
|
||||
messageBus,
|
||||
aggregator,
|
||||
cancellationTokenSource,
|
||||
TestCaseDisplayName,
|
||||
SkipReason,
|
||||
explicitOption,
|
||||
constructorArguments))
|
||||
.GetAwaiter()
|
||||
.GetResult();
|
||||
|
||||
return Task.FromResult(runSummary);
|
||||
return runSummary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,103 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Threading;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal class AvaloniaTestCaseRunner : XunitTestCaseRunner
|
||||
internal sealed class AvaloniaTestCaseRunner
|
||||
: XunitTestCaseRunnerBase<AvaloniaTestCaseRunnerContext, IXunitTestCase, IXunitTest>
|
||||
{
|
||||
private readonly HeadlessUnitTestSession _session;
|
||||
private readonly Action? _onAfterTestInvoked;
|
||||
public static AvaloniaTestCaseRunner Instance { get; } = new();
|
||||
|
||||
public AvaloniaTestCaseRunner(
|
||||
HeadlessUnitTestSession session, Action? onAfterTestInvoked,
|
||||
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)
|
||||
private AvaloniaTestCaseRunner()
|
||||
{
|
||||
_session = session;
|
||||
_onAfterTestInvoked = onAfterTestInvoked;
|
||||
}
|
||||
|
||||
public static Task<RunSummary> RunTest(HeadlessUnitTestSession session,
|
||||
IXunitTestCase testCase, string displayName, string skipReason, object[] constructorArguments,
|
||||
object[] testMethodArguments, IMessageBus messageBus, ExceptionAggregator aggregator,
|
||||
CancellationTokenSource cancellationTokenSource)
|
||||
public async ValueTask<RunSummary> Run(
|
||||
IXunitTestCase testCase,
|
||||
IReadOnlyCollection<IXunitTest> tests,
|
||||
IMessageBus messageBus,
|
||||
ExceptionAggregator aggregator,
|
||||
CancellationTokenSource cancellationTokenSource,
|
||||
string displayName,
|
||||
string? skipReason,
|
||||
ExplicitOption explicitOption,
|
||||
object?[] constructorArguments)
|
||||
{
|
||||
var afterTest = () => Dispatcher.UIThread.RunJobs();
|
||||
var session = HeadlessUnitTestSession.GetOrStartForAssembly(testCase.TestClass.Class.Assembly);
|
||||
|
||||
var runner = new AvaloniaTestCaseRunner(session, afterTest, testCase, displayName,
|
||||
skipReason, constructorArguments, testMethodArguments, messageBus, aggregator, cancellationTokenSource);
|
||||
return runner.RunAsync();
|
||||
await using var ctxt = new AvaloniaTestCaseRunnerContext(
|
||||
testCase,
|
||||
tests,
|
||||
messageBus,
|
||||
aggregator,
|
||||
cancellationTokenSource,
|
||||
displayName,
|
||||
skipReason,
|
||||
explicitOption,
|
||||
constructorArguments,
|
||||
session);
|
||||
await ctxt.InitializeAsync();
|
||||
|
||||
return await Run(ctxt);
|
||||
}
|
||||
|
||||
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 AvaloniaTestRunner(_session, _onAfterTestInvoked, test, messageBus, testClass, constructorArguments,
|
||||
testMethod, testMethodArguments, skipReason, beforeAfterAttributes, aggregator, cancellationTokenSource);
|
||||
}
|
||||
|
||||
private class AvaloniaTestRunner : XunitTestRunner
|
||||
{
|
||||
private readonly HeadlessUnitTestSession _session;
|
||||
private readonly Action? _onAfterTestInvoked;
|
||||
|
||||
public AvaloniaTestRunner(
|
||||
HeadlessUnitTestSession session, Action? onAfterTestInvoked,
|
||||
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)
|
||||
{
|
||||
_session = session;
|
||||
_onAfterTestInvoked = onAfterTestInvoked;
|
||||
}
|
||||
|
||||
protected override Task<decimal> InvokeTestMethodAsync(ExceptionAggregator aggregator)
|
||||
{
|
||||
return _session.Dispatch(
|
||||
() => new AvaloniaTestInvoker(_onAfterTestInvoked, Test, MessageBus, TestClass,
|
||||
ConstructorArguments, TestMethod, TestMethodArguments, BeforeAfterAttributes, aggregator,
|
||||
CancellationTokenSource).RunAsync(),
|
||||
CancellationTokenSource.Token);
|
||||
}
|
||||
}
|
||||
|
||||
private class AvaloniaTestInvoker : XunitTestInvoker
|
||||
{
|
||||
private readonly Action? _onAfterTestInvoked;
|
||||
|
||||
public AvaloniaTestInvoker(
|
||||
Action? onAfterTestInvoked,
|
||||
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)
|
||||
{
|
||||
_onAfterTestInvoked = onAfterTestInvoked;
|
||||
}
|
||||
|
||||
protected override async Task AfterTestMethodInvokedAsync()
|
||||
{
|
||||
await base.AfterTestMethodInvokedAsync();
|
||||
|
||||
// Only here we can execute random code after the test, where exception will be properly handled by the XUnit.
|
||||
if (_onAfterTestInvoked is not null)
|
||||
{
|
||||
Aggregator.Run(_onAfterTestInvoked);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override ValueTask<RunSummary> RunTest(
|
||||
AvaloniaTestCaseRunnerContext ctxt,
|
||||
IXunitTest test)
|
||||
=> AvaloniaTestRunner.Instance.Run(
|
||||
test,
|
||||
ctxt.MessageBus,
|
||||
ctxt.ConstructorArguments,
|
||||
ctxt.ExplicitOption,
|
||||
ctxt.Aggregator.Clone(),
|
||||
ctxt.CancellationTokenSource,
|
||||
ctxt.BeforeAfterTestAttributes,
|
||||
ctxt.Session);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal sealed class AvaloniaTestCaseRunnerContext(
|
||||
IXunitTestCase testCase,
|
||||
IReadOnlyCollection<IXunitTest> tests,
|
||||
IMessageBus messageBus,
|
||||
ExceptionAggregator aggregator,
|
||||
CancellationTokenSource cancellationTokenSource,
|
||||
string displayName,
|
||||
string? skipReason,
|
||||
ExplicitOption explicitOption,
|
||||
object?[] constructorArguments,
|
||||
HeadlessUnitTestSession session)
|
||||
: XunitTestCaseRunnerContext(
|
||||
testCase,
|
||||
tests,
|
||||
messageBus,
|
||||
aggregator,
|
||||
cancellationTokenSource,
|
||||
displayName,
|
||||
skipReason,
|
||||
explicitOption,
|
||||
constructorArguments)
|
||||
{
|
||||
public HeadlessUnitTestSession Session { get; } = session;
|
||||
}
|
||||
@@ -1,35 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
using System.Reflection;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal class AvaloniaTestFramework : XunitTestFramework
|
||||
internal sealed class AvaloniaTestFramework : XunitTestFramework
|
||||
{
|
||||
public AvaloniaTestFramework(IMessageSink messageSink) : base(messageSink)
|
||||
{
|
||||
}
|
||||
protected override ITestFrameworkDiscoverer CreateDiscoverer(Assembly assembly)
|
||||
=> new AvaloniaTestFrameworkDiscoverer(new XunitTestAssembly(assembly, null, assembly.GetName().Version));
|
||||
|
||||
protected override ITestFrameworkExecutor CreateExecutor(AssemblyName assemblyName)
|
||||
=> new Executor(assemblyName, SourceInformationProvider, DiagnosticMessageSink);
|
||||
|
||||
|
||||
private class Executor : XunitTestFrameworkExecutor
|
||||
{
|
||||
public Executor(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 AvaloniaTestAssemblyRunner(
|
||||
TestAssembly, testCases, DiagnosticMessageSink, executionMessageSink,
|
||||
executionOptions)) await assemblyRunner.RunAsync();
|
||||
}
|
||||
}
|
||||
protected override ITestFrameworkExecutor CreateExecutor(Assembly assembly)
|
||||
=> new AvaloniaTestFrameworkExecutor(new XunitTestAssembly(assembly, null, assembly.GetName().Version));
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
@@ -12,27 +9,9 @@ namespace Avalonia.Headless.XUnit;
|
||||
/// <remarks>
|
||||
/// It is an alternative to using [AvaloniaFact] or [AvaloniaTheory] attributes on every test method.
|
||||
/// </remarks>
|
||||
[TestFrameworkDiscoverer("Avalonia.Headless.XUnit.AvaloniaTestFrameworkTypeDiscoverer", "Avalonia.Headless.XUnit")]
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)]
|
||||
public sealed class AvaloniaTestFrameworkAttribute : Attribute, ITestFrameworkAttribute
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Discoverer implementation for the Avalonia testing framework.
|
||||
/// </summary>
|
||||
public class AvaloniaTestFrameworkTypeDiscoverer : ITestFrameworkTypeDiscoverer
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates instance of <see cref="AvaloniaTestFrameworkTypeDiscoverer"/>.
|
||||
/// </summary>
|
||||
public AvaloniaTestFrameworkTypeDiscoverer(IMessageSink _)
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Type GetTestFrameworkType(IAttributeInfo attribute)
|
||||
{
|
||||
return typeof(AvaloniaTestFramework);
|
||||
}
|
||||
public Type FrameworkType
|
||||
=> typeof(AvaloniaTestFramework);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Xunit;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal sealed class AvaloniaTestFrameworkDiscoverer : XunitTestFrameworkDiscoverer
|
||||
{
|
||||
public AvaloniaTestFrameworkDiscoverer(
|
||||
IXunitTestAssembly testAssembly,
|
||||
IXunitTestCollectionFactory? collectionFactory = null)
|
||||
: base(testAssembly, collectionFactory)
|
||||
{
|
||||
DiscovererTypeCache[typeof(FactAttribute)] = typeof(AvaloniaFactDiscoverer);
|
||||
DiscovererTypeCache[typeof(TheoryAttribute)] = typeof(AvaloniaTheoryDiscoverer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System.Threading.Tasks;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal sealed class AvaloniaTestFrameworkExecutor(IXunitTestAssembly testAssembly)
|
||||
: XunitTestFrameworkExecutor(testAssembly)
|
||||
{
|
||||
private readonly HeadlessUnitTestSession _session = HeadlessUnitTestSession.GetOrStartForAssembly(testAssembly.Assembly);
|
||||
|
||||
protected override ITestFrameworkDiscoverer CreateDiscoverer()
|
||||
=> new AvaloniaTestFrameworkDiscoverer(TestAssembly);
|
||||
|
||||
public override async ValueTask DisposeAsync()
|
||||
{
|
||||
await _session.DisposeAsync();
|
||||
await base.DisposeAsync();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia.Threading;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal sealed class AvaloniaTestRunner : XunitTestRunnerBase<AvaloniaTestRunnerContext, IXunitTest>
|
||||
{
|
||||
public static AvaloniaTestRunner Instance { get; } = new();
|
||||
|
||||
private AvaloniaTestRunner()
|
||||
{
|
||||
}
|
||||
|
||||
public async ValueTask<RunSummary> Run(
|
||||
IXunitTest test,
|
||||
IMessageBus messageBus,
|
||||
object?[] constructorArguments,
|
||||
ExplicitOption explicitOption,
|
||||
ExceptionAggregator aggregator,
|
||||
CancellationTokenSource cancellationTokenSource,
|
||||
IReadOnlyCollection<IBeforeAfterTestAttribute> beforeAfterAttributes,
|
||||
HeadlessUnitTestSession session)
|
||||
{
|
||||
await using var ctxt = new AvaloniaTestRunnerContext(
|
||||
test,
|
||||
messageBus,
|
||||
explicitOption,
|
||||
aggregator,
|
||||
cancellationTokenSource,
|
||||
beforeAfterAttributes,
|
||||
constructorArguments,
|
||||
session
|
||||
);
|
||||
await ctxt.InitializeAsync();
|
||||
|
||||
return await session.Dispatch(
|
||||
async () =>
|
||||
{
|
||||
var dispatcher = Dispatcher.UIThread;
|
||||
var summary = await Run(ctxt);
|
||||
dispatcher.RunJobs();
|
||||
return summary;
|
||||
},
|
||||
ctxt.CancellationTokenSource.Token);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal sealed class AvaloniaTestRunnerContext(
|
||||
IXunitTest test,
|
||||
IMessageBus messageBus,
|
||||
ExplicitOption explicitOption,
|
||||
ExceptionAggregator aggregator,
|
||||
CancellationTokenSource cancellationTokenSource,
|
||||
IReadOnlyCollection<IBeforeAfterTestAttribute> beforeAfterTestAttributes,
|
||||
object?[] constructorArguments,
|
||||
HeadlessUnitTestSession session)
|
||||
: XunitTestRunnerContext(
|
||||
test,
|
||||
messageBus,
|
||||
explicitOption,
|
||||
aggregator,
|
||||
cancellationTokenSource,
|
||||
beforeAfterTestAttributes,
|
||||
constructorArguments)
|
||||
{
|
||||
public HeadlessUnitTestSession Session { get; } = session;
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
@@ -12,26 +9,5 @@ namespace Avalonia.Headless.XUnit;
|
||||
/// such that awaited expressions resume on the test's "main thread".
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||
[XunitTestCaseDiscoverer("Avalonia.Headless.XUnit.AvaloniaTheoryDiscoverer", "Avalonia.Headless.XUnit")]
|
||||
public sealed class AvaloniaTheoryAttribute : TheoryAttribute
|
||||
{
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class AvaloniaTheoryDiscoverer : TheoryDiscoverer
|
||||
{
|
||||
public AvaloniaTheoryDiscoverer(IMessageSink diagnosticMessageSink)
|
||||
: base(diagnosticMessageSink)
|
||||
{
|
||||
}
|
||||
|
||||
protected override IEnumerable<IXunitTestCase> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow)
|
||||
{
|
||||
yield return new AvaloniaTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, dataRow);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IXunitTestCase> CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute)
|
||||
{
|
||||
yield return new AvaloniaTheoryTestCase(DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod);
|
||||
}
|
||||
}
|
||||
[XunitTestCaseDiscoverer(typeof(AvaloniaTheoryDiscoverer))]
|
||||
public sealed class AvaloniaTheoryAttribute : TheoryAttribute;
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit;
|
||||
using Xunit.Internal;
|
||||
using Xunit.Sdk;
|
||||
using Xunit.v3;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public class AvaloniaTheoryDiscoverer : TheoryDiscoverer
|
||||
{
|
||||
protected override ValueTask<IReadOnlyCollection<IXunitTestCase>> CreateTestCasesForDataRow(
|
||||
ITestFrameworkDiscoveryOptions discoveryOptions,
|
||||
IXunitTestMethod testMethod,
|
||||
ITheoryAttribute theoryAttribute,
|
||||
ITheoryDataRow dataRow,
|
||||
object?[] testMethodArguments)
|
||||
{
|
||||
var details = TestIntrospectionHelper.GetTestCaseDetailsForTheoryDataRow(
|
||||
discoveryOptions,
|
||||
testMethod,
|
||||
theoryAttribute,
|
||||
dataRow,
|
||||
testMethodArguments);
|
||||
var traits = TestIntrospectionHelper.GetTraits(testMethod, dataRow);
|
||||
|
||||
var testCase = new AvaloniaTestCase(
|
||||
details.ResolvedTestMethod,
|
||||
details.TestCaseDisplayName,
|
||||
details.UniqueID,
|
||||
details.Explicit,
|
||||
details.SkipExceptions,
|
||||
details.SkipReason,
|
||||
details.SkipType,
|
||||
details.SkipUnless,
|
||||
details.SkipWhen,
|
||||
traits,
|
||||
testMethodArguments,
|
||||
sourceFilePath: details.SourceFilePath,
|
||||
sourceLineNumber: details.SourceLineNumber,
|
||||
timeout: details.Timeout);
|
||||
|
||||
return ValueTask.FromResult<IReadOnlyCollection<IXunitTestCase>>([testCase]);
|
||||
}
|
||||
|
||||
protected override ValueTask<IReadOnlyCollection<IXunitTestCase>> CreateTestCasesForTheory(
|
||||
ITestFrameworkDiscoveryOptions discoveryOptions,
|
||||
IXunitTestMethod testMethod,
|
||||
ITheoryAttribute theoryAttribute)
|
||||
{
|
||||
var details = TestIntrospectionHelper.GetTestCaseDetails(discoveryOptions, testMethod, theoryAttribute);
|
||||
|
||||
var testCase =
|
||||
details.SkipReason is not null && details.SkipUnless is null && details.SkipWhen is null
|
||||
? new AvaloniaTestCase(
|
||||
details.ResolvedTestMethod,
|
||||
details.TestCaseDisplayName,
|
||||
details.UniqueID,
|
||||
details.Explicit,
|
||||
details.SkipExceptions,
|
||||
details.SkipReason,
|
||||
details.SkipType,
|
||||
details.SkipUnless,
|
||||
details.SkipWhen,
|
||||
testMethod.Traits.ToReadWrite(StringComparer.OrdinalIgnoreCase),
|
||||
sourceFilePath: details.SourceFilePath,
|
||||
sourceLineNumber: details.SourceLineNumber,
|
||||
timeout: details.Timeout
|
||||
)
|
||||
: (IXunitTestCase)new AvaloniaDelayEnumeratedTheoryTestCase(
|
||||
details.ResolvedTestMethod,
|
||||
details.TestCaseDisplayName,
|
||||
details.UniqueID,
|
||||
details.Explicit,
|
||||
theoryAttribute.SkipTestWithoutData,
|
||||
details.SkipExceptions,
|
||||
details.SkipReason,
|
||||
details.SkipType,
|
||||
details.SkipUnless,
|
||||
details.SkipWhen,
|
||||
testMethod.Traits.ToReadWrite(StringComparer.OrdinalIgnoreCase),
|
||||
sourceFilePath: details.SourceFilePath,
|
||||
sourceLineNumber: details.SourceLineNumber,
|
||||
timeout: details.Timeout
|
||||
);
|
||||
|
||||
return ValueTask.FromResult<IReadOnlyCollection<IXunitTestCase>>([testCase]);
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Xunit.Abstractions;
|
||||
using Xunit.Sdk;
|
||||
|
||||
namespace Avalonia.Headless.XUnit;
|
||||
|
||||
internal class AvaloniaTheoryTestCase : XunitTheoryTestCase
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")]
|
||||
public AvaloniaTheoryTestCase()
|
||||
{
|
||||
}
|
||||
|
||||
public AvaloniaTheoryTestCase(IMessageSink diagnosticMessageSink, TestMethodDisplay defaultMethodDisplay, TestMethodDisplayOptions defaultMethodDisplayOptions, ITestMethod testMethod)
|
||||
: base(diagnosticMessageSink, defaultMethodDisplay, defaultMethodDisplayOptions, testMethod)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<RunSummary> RunAsync(IMessageSink diagnosticMessageSink, IMessageBus messageBus, object[] constructorArguments, ExceptionAggregator aggregator, CancellationTokenSource cancellationTokenSource)
|
||||
{
|
||||
var session = HeadlessUnitTestSession.GetOrStartForAssembly(Method.ToRuntimeMethod().DeclaringType?.Assembly);
|
||||
|
||||
return AvaloniaTestCaseRunner
|
||||
.RunTest(session, this, DisplayName, SkipReason, constructorArguments,
|
||||
TestMethodArguments, messageBus, aggregator, cancellationTokenSource);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Avalonia.Headless;
|
||||
/// All UI tests are supposed to be executed from one of the <see cref="Dispatch"/> methods to keep execution flow on the UI thread.
|
||||
/// Disposing unit test session stops internal dispatcher loop.
|
||||
/// </summary>
|
||||
public sealed class HeadlessUnitTestSession : IDisposable
|
||||
public sealed class HeadlessUnitTestSession : IDisposable, IAsyncDisposable
|
||||
{
|
||||
private static readonly Dictionary<Assembly, HeadlessUnitTestSession> s_session = new();
|
||||
|
||||
@@ -184,6 +184,14 @@ public sealed class HeadlessUnitTestSession : IDisposable
|
||||
_cancellationTokenSource.Dispose();
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
await _cancellationTokenSource.CancelAsync().ConfigureAwait(false);
|
||||
_queue.CompleteAdding();
|
||||
await _dispatchTask.ConfigureAwait(false);
|
||||
_cancellationTokenSource.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates instance of <see cref="HeadlessUnitTestSession"/>.
|
||||
/// </summary>
|
||||
|
||||
-1
@@ -4,7 +4,6 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<DefineConstants>$(DefineConstants);XUNIT</DefineConstants>
|
||||
<IsXUnit2>true</IsXUnit2>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\build\UnitTests.NetCore.targets" />
|
||||
|
||||
-1
@@ -4,7 +4,6 @@
|
||||
<OutputType>Exe</OutputType>
|
||||
<IsTestProject>true</IsTestProject>
|
||||
<DefineConstants>$(DefineConstants);XUNIT</DefineConstants>
|
||||
<IsXUnit2>true</IsXUnit2>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\..\build\UnitTests.NetCore.targets" />
|
||||
|
||||
@@ -13,10 +13,7 @@
|
||||
<ProjectReference Include="../../src/Avalonia.Themes.Fluent/Avalonia.Themes.Fluent.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="xunit.v3.mtp-v2" Version="3.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<Import Project="../../build/XUnit.props" />
|
||||
<Import Project="../../build/SharedVersion.props" />
|
||||
<Import Project="../../build/ReferenceCoreLibraries.props" />
|
||||
<Import Project="../../build/BuildTargets.targets" />
|
||||
|
||||
Reference in New Issue
Block a user