Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Target xUnit v3 for our v2 release #118

Merged
merged 28 commits into from
Jan 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
1039753
Work toward xunit v3
AArnott Dec 30, 2024
f8bfb61
More work
AArnott Dec 30, 2024
cf1e550
Updated xunit.runner.console to v3 package.
reduckted Jan 7, 2025
25073fb
Removed azure-pipelines.yml from solution.
reduckted Jan 7, 2025
0efd1f2
Updated `XunitTestCaseDiscoverer` attributes.
reduckted Jan 7, 2025
f1d4919
Updated discoverer types.
reduckted Jan 7, 2025
3f6b9cb
Updated test case creation.
reduckted Jan 8, 2025
05ff98f
Implemented the test runner.
reduckted Jan 10, 2025
b8aef61
Implemented new IAsyncLifetime interface corretly.
reduckted Jan 10, 2025
b0c3d83
Used `xunit.v3.extensibility.core` instead of `xunit.v3.core`.
reduckted Jan 10, 2025
04a1523
Fixed analyzer warnings.
reduckted Jan 10, 2025
461feb9
Fixed compilation error in `CocoaSynchronizationContext`.
reduckted Jan 10, 2025
f41c7e4
Fix compiler warnings
AArnott Jan 16, 2025
d89f0be
Drop support for `async void` tests
AArnott Jan 16, 2025
1bbadb9
Avoid `async void` tests within our own tests
AArnott Jan 16, 2025
0495b94
Pass test method arguments when creating UITestCase.
reduckted Jan 16, 2025
9c2148e
Set synchronization context when running test.
reduckted Jan 17, 2025
5c3a2d5
Removed unused properties.
reduckted Jan 17, 2025
be1e48a
Add disposal SyncContext test for StaFact
AArnott Jan 17, 2025
1f8cdff
Merge remote-tracking branch 'origin/main' into xunitv3
AArnott Jan 17, 2025
b522534
Document versions to use for xUnit v2 and v3 support
AArnott Jan 17, 2025
ea0a5cb
Update CONTRIBUTING.md
AArnott Jan 17, 2025
9192cbf
Fix compile warning
AArnott Jan 17, 2025
3b4dc05
Fixed test case serialization of `SyncContextType`.
reduckted Jan 18, 2025
4de628f
Avoided casting enum to int.
reduckted Jan 18, 2025
24d2aa8
Prevented data row test cases from being reported as duplicate tests.
reduckted Jan 18, 2025
c56047b
Fixed Mac tests not running
reduckted Jan 18, 2025
8825e35
Capture logs from running tests
AArnott Jan 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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