Skip to content

Commit

Permalink
Merge pull request #118 from AArnott/xunitv3
Browse files Browse the repository at this point in the history
Target xUnit v3 for our v2 release
  • Loading branch information
AArnott authored Jan 18, 2025
2 parents 30b7f2e + 8825e35 commit 4a13264
Show file tree
Hide file tree
Showing 67 changed files with 1,427 additions and 963 deletions.
4 changes: 2 additions & 2 deletions .github/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"groupName": "nbgv and nerdbank.gitversioning updates"
},
{
"matchPackageNames": ["xunit.extensibility.execution", "xunit"],
"allowedVersions": "<=2.4.2"
"matchPackageNames": ["xunit*"],
"groupName": "xunit"
},
{
"matchDatasources": ["dotnet-version", "docker"],
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
run: tools/dotnet-test-cloud.ps1 -Configuration ${{ env.BUILDCONFIGURATION }} -Agent ${{ runner.os }}
shell: pwsh
- name: 🧪 mac-specific test
run: dotnet build -c ${{ env.BUILDCONFIGURATION }} -t:Test -p:BuildProjectReferences=false
run: dotnet build -c ${{ env.BUILDCONFIGURATION }} -t:Test -p:BuildProjectReferences=false -p:TestLogs="${{ runner.temp }}/_artifacts/test_logs/" -bl:"${{ runner.temp }}/_artifacts/build_logs/macos-test.binlog"
working-directory: test/Xunit.StaFact.Tests.Mac
if: success() && runner.os == 'macos'
- name: 💅🏻 Verify formatted code
Expand Down
6 changes: 5 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ with any additional questions or comments.
* Use Windows PowerShell or [PowerShell Core][pwsh] (including on Linux/OSX) to run .ps1 scripts.
Some scripts set environment variables to help you, but they are only retained if you use PowerShell as your shell.

## Branches

xUnit v2 support is maintained in the `v1.x` branch, while xUnit v3 is maintained in the `main` branch.

## Prerequisites

The only prerequisite for building, testing, and deploying from this repository
Expand All @@ -20,7 +24,7 @@ You should install the version specified in `global.json` or a later version wit
the same major.minor.Bxx "hundreds" band.
For example if 2.2.300 is specified, you may install 2.2.300, 2.2.301, or 2.2.310
while the 2.2.400 version would not be considered compatible by .NET SDK.
See [.NET Core Versioning](https://docs.microsoft.com/en-us/dotnet/core/versions/) for more information.
See [.NET Core Versioning](https://docs.microsoft.com/dotnet/core/versions/) for more information.

All dependencies can be installed by running the `init.ps1` script at the root of the repository
using Windows PowerShell or [PowerShell Core][pwsh] (on any OS).
Expand Down
5 changes: 2 additions & 3 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Microsoft.CodeAnalysis.PublicApiAnalyzers" Version="3.3.4" />
<PackageVersion Include="xunit.extensibility.execution" Version="2.4.2" />
<PackageVersion Include="xunit.runner.console" Version="2.9.3" />
<PackageVersion Include="xunit.v3.extensibility.core" Version="1.0.0" />
</ItemGroup>
<ItemGroup Label="Library.Template">
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.0.1" />
<PackageVersion Include="xunit" Version="2.4.2" />
<PackageVersion Include="xunit.v3" Version="1.0.0" />
</ItemGroup>
<ItemGroup>
<!-- Put repo-specific GlobalPackageReference items in this group. -->
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ Simply use `[WpfFact]`, `[WinFormsFact]`, `[StaFact]` or the cross-platform `[UI

Theory variants of these attributes allow for parameterized testing. Check out the xunit.combinatorial nuget package for pairwise or combinatorial testing with theories.

## xUnit v2 vs. v3

With xUnit v3 now available with breaking changes from v2, see the following table for how we support both versions:

xUnit | Xunit.STAFact
--|--
For xUnit v2 support | Use Xunit.STAFact 1.x
For xUnit v3 support | Use Xunit.STAFact 2.x+

## Features

The following test attributes are supported:
Expand Down
1 change: 0 additions & 1 deletion Xunit.StaFact.sln
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
.gitignore = .gitignore
azure-pipelines.yml = azure-pipelines.yml
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
Directory.Packages.props = Directory.Packages.props
Expand Down
4 changes: 2 additions & 2 deletions src/Xunit.StaFact/Mac/CocoaFactAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE file in the project root for full license information.

using Xunit.Sdk;
Expand All @@ -10,7 +10,7 @@ namespace Xunit;
/// running on <see cref="Foundation.NSRunLoop.Main"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer("Xunit.Sdk.CocoaFactDiscoverer", ThisAssembly.AssemblyName)]
[XunitTestCaseDiscoverer(typeof(CocoaFactDiscoverer))]
public class CocoaFactAttribute : FactAttribute
{
}
4 changes: 2 additions & 2 deletions src/Xunit.StaFact/Mac/CocoaTheoryAttribute.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE file in the project root for full license information.

using Xunit.Sdk;
Expand All @@ -10,7 +10,7 @@ namespace Xunit;
/// running on <see cref="Foundation.NSRunLoop.Main"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
[XunitTestCaseDiscoverer("Xunit.Sdk.CocoaTheoryDiscoverer", ThisAssembly.AssemblyName)]
[XunitTestCaseDiscoverer(typeof(CocoaTheoryDiscoverer))]
public class CocoaTheoryAttribute : TheoryAttribute
{
}
33 changes: 4 additions & 29 deletions src/Xunit.StaFact/Sdk.Mac/CocoaFactDiscoverer.cs
Original file line number Diff line number Diff line change
@@ -1,41 +1,16 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE file in the project root for full license information.

using System.Runtime.CompilerServices;

namespace Xunit.Sdk;

/// <summary>
/// The discovery class for <see cref="CocoaFactDiscoverer"/>.
/// </summary>
public class CocoaFactDiscoverer : FactDiscoverer
{
private readonly IMessageSink diagnosticMessageSink;

/// <summary>
/// Initializes a new instance of the <see cref="CocoaFactDiscoverer"/> class.
/// </summary>
/// <param name="diagnosticMessageSink">The diagnostic message sink.</param>
public CocoaFactDiscoverer(IMessageSink diagnosticMessageSink)
: base(diagnosticMessageSink)
/// <inheritdoc/>
protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, IFactAttribute factAttribute)
{
this.diagnosticMessageSink = diagnosticMessageSink;
}

protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
{
if (testMethod is null)
{
throw new ArgumentNullException(nameof(testMethod));
}

if (testMethod.Method.ReturnType.Name == "System.Void" &&
testMethod.Method.GetCustomAttributes(typeof(AsyncStateMachineAttribute)).Any())
{
return new ExecutionErrorTestCase(this.diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod, "Async void methods are not supported.");
}

UISettingsAttribute settings = UIFactDiscoverer.GetSettings(testMethod);
return new UITestCase(UITestCase.SyncContextType.Cocoa, this.diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, testMethodArguments: null, settings);
return CocoaUtilities.CreateTestCaseForFact(discoveryOptions, testMethod, factAttribute);
}
}
6 changes: 3 additions & 3 deletions src/Xunit.StaFact/Sdk.Mac/CocoaSynchronizationContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE file in the project root for full license information.

namespace Xunit.Sdk;
Expand Down Expand Up @@ -171,9 +171,9 @@ private bool TryOneWorkItem()

try
{
if (this.aggregator is object)
if (this.aggregator.HasValue)
{
this.aggregator.Run(() => work.Key(work.Value));
this.aggregator.Value.Run(() => work.Key(work.Value));
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,8 @@ private CocoaSynchronizationContextAdapter()
{
}

internal override bool CanCompleteOperations => true;

internal override SynchronizationContext Create(string name) => new CocoaSynchronizationContext(name, this.ShouldSetAsCurrent);

internal override Task WaitForOperationCompletionAsync(SynchronizationContext syncContext) => ((CocoaSynchronizationContext)syncContext).WaitForOperationCompletionAsync();

internal override void PumpTill(SynchronizationContext synchronizationContext, Task task)
{
((CocoaSynchronizationContext)synchronizationContext).PumpMessages(task);
Expand Down
33 changes: 17 additions & 16 deletions src/Xunit.StaFact/Sdk.Mac/CocoaTheoryDiscoverer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE file in the project root for full license information.

namespace Xunit.Sdk;
Expand All @@ -8,24 +8,25 @@ namespace Xunit.Sdk;
/// </summary>
public class CocoaTheoryDiscoverer : TheoryDiscoverer
{
/// <summary>
/// Initializes a new instance of the <see cref="CocoaTheoryDiscoverer"/> class.
/// </summary>
/// <param name="diagnosticMessageSink">The diagnostic message sink.</param>
public CocoaTheoryDiscoverer(IMessageSink diagnosticMessageSink)
: base(diagnosticMessageSink)
/// <inheritdoc/>
protected override ValueTask<IReadOnlyCollection<IXunitTestCase>> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, ITheoryAttribute theoryAttribute, ITheoryDataRow dataRow, object?[] testMethodArguments)
{
IXunitTestCase testCase = CocoaUtilities.CreateTestCaseForDataRow(
discoveryOptions,
testMethod,
theoryAttribute,
dataRow,
testMethodArguments);
return new([testCase]);
}

protected override IEnumerable<IXunitTestCase> CreateTestCasesForDataRow(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute, object[] dataRow)
/// <inheritdoc/>
protected override ValueTask<IReadOnlyCollection<IXunitTestCase>> CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, ITheoryAttribute theoryAttribute)
{
UISettingsAttribute settings = UIFactDiscoverer.GetSettings(testMethod);
yield return new UITestCase(UITestCase.SyncContextType.Cocoa, this.DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, dataRow, settings);
}

protected override IEnumerable<IXunitTestCase> CreateTestCasesForTheory(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo theoryAttribute)
{
UISettingsAttribute settings = UIFactDiscoverer.GetSettings(testMethod);
yield return new UITheoryTestCase(UITestCase.SyncContextType.Cocoa, this.DiagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod, settings);
IXunitTestCase testCase = CocoaUtilities.CreateTestCaseForTheory(
discoveryOptions,
testMethod,
theoryAttribute);
return new([testCase]);
}
}
53 changes: 53 additions & 0 deletions src/Xunit.StaFact/Sdk.Mac/CocoaUtilities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE file in the project root for full license information.

namespace Xunit.Sdk;

internal static class CocoaUtilities
{
private const UITestCase.SyncContextType ContextType = UITestCase.SyncContextType.Cocoa;
private const string? SkipReason = null;

internal static IXunitTestCase CreateTestCaseForFact(
ITestFrameworkDiscoveryOptions discoveryOptions,
IXunitTestMethod testMethod,
IFactAttribute factAttribute)
{
return Utilities.CreateTestCaseForFact(
ContextType,
SkipReason,
discoveryOptions,
testMethod,
factAttribute);
}

internal static IXunitTestCase CreateTestCaseForDataRow(
ITestFrameworkDiscoveryOptions discoveryOptions,
IXunitTestMethod testMethod,
ITheoryAttribute theoryAttribute,
ITheoryDataRow dataRow,
object?[] testMethodArguments)
{
return Utilities.CreateTestCaseForDataRow(
ContextType,
SkipReason,
discoveryOptions,
testMethod,
theoryAttribute,
dataRow,
testMethodArguments);
}

internal static IXunitTestCase CreateTestCaseForTheory(
ITestFrameworkDiscoveryOptions discoveryOptions,
IXunitTestMethod testMethod,
ITheoryAttribute theoryAttribute)
{
return Utilities.CreateTestCaseForTheory(
ContextType,
SkipReason,
discoveryOptions,
testMethod,
theoryAttribute);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,8 @@ private DispatcherSynchronizationContextAdapter()
{
}

internal override bool CanCompleteOperations => false;

internal override SynchronizationContext Create(string name) => new DispatcherSynchronizationContext();

internal override Task WaitForOperationCompletionAsync(SynchronizationContext syncContext)
{
throw new NotSupportedException("Async void test methods are not supported by the WPF dispatcher. Use Async Task instead.");
}

internal override void PumpTill(SynchronizationContext synchronizationContext, Task task)
{
if (!task.IsCompleted)
Expand Down
39 changes: 7 additions & 32 deletions src/Xunit.StaFact/Sdk.WindowsDesktop/WinFormsFactDiscoverer.cs
Original file line number Diff line number Diff line change
@@ -1,44 +1,19 @@
// Copyright (c) Andrew Arnott. All rights reserved.
// Copyright (c) Andrew Arnott. All rights reserved.
// Licensed under the Ms-PL license. See LICENSE file in the project root for full license information.

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace Xunit.Sdk;

/// <summary>
/// The discovery class for <see cref="WinFormsFactAttribute"/>.
/// </summary>
public class WinFormsFactDiscoverer : FactDiscoverer
{
private readonly IMessageSink diagnosticMessageSink;

/// <summary>
/// Initializes a new instance of the <see cref="WinFormsFactDiscoverer"/> class.
/// </summary>
/// <param name="diagnosticMessageSink">The diagnostic message sink.</param>
public WinFormsFactDiscoverer(IMessageSink diagnosticMessageSink)
: base(diagnosticMessageSink)
/// <inheritdoc/>
protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, IXunitTestMethod testMethod, IFactAttribute factAttribute)
{
this.diagnosticMessageSink = diagnosticMessageSink;
}

protected override IXunitTestCase CreateTestCase(ITestFrameworkDiscoveryOptions discoveryOptions, ITestMethod testMethod, IAttributeInfo factAttribute)
{
if (testMethod is null)
{
throw new ArgumentNullException(nameof(testMethod));
}

if (testMethod.Method.ReturnType.Name == "System.Void" &&
testMethod.Method.GetCustomAttributes(typeof(AsyncStateMachineAttribute)).Any())
{
return new ExecutionErrorTestCase(this.diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), TestMethodDisplayOptions.None, testMethod, "Async void methods are not supported.");
}

UISettingsAttribute settings = UIFactDiscoverer.GetSettings(testMethod);
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
? new UITestCase(UITestCase.SyncContextType.WinForms, this.diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), testMethod, testMethodArguments: null, settings)
: new XunitSkippedDataRowTestCase(this.diagnosticMessageSink, discoveryOptions.MethodDisplayOrDefault(), discoveryOptions.MethodDisplayOptionsOrDefault(), testMethod, "WinForms only exists on Windows.");
return WinFormsUtilities.CreateTestCaseForFact(
discoveryOptions,
testMethod,
factAttribute);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,8 @@ private WinFormsSynchronizationContextAdapter()
{
}

internal override bool CanCompleteOperations => false;

internal override SynchronizationContext Create(string name) => new WindowsFormsSynchronizationContext();

internal override Task WaitForOperationCompletionAsync(SynchronizationContext syncContext)
{
throw new NotSupportedException("Async void test methods are not supported by the WinForms dispatcher. Use Async Task instead.");
}

internal override void PumpTill(SynchronizationContext synchronizationContext, Task task)
{
while (!task.IsCompleted)
Expand Down
Loading

0 comments on commit 4a13264

Please sign in to comment.