Skip to content

Commit

Permalink
Add Task<T>, ValueTask, and ValueTask<T> to xUnit1030
Browse files Browse the repository at this point in the history
  • Loading branch information
bradwilson committed Aug 2, 2023
1 parent 0ec4023 commit 3de1575
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public async Task TestMethod() {
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void FailureCase_Async(string argumentValue)
public async void FailureCase_Task_Async(string argumentValue)
{
var source = @$"
using System.Threading.Tasks;
Expand All @@ -44,7 +44,7 @@ public async Task TestMethod() {{
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void FailureCase_NonAsync(string argumentValue)
public async void FailureCase_Task_NonAsync(string argumentValue)
{
var source = @$"
using System.Threading.Tasks;
Expand All @@ -60,6 +60,69 @@ public void TestMethod() {{
await Verify.VerifyAnalyzer(source);
}

[Theory]
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void FailureCase_TaskOfT(string argumentValue)
{
var source = @$"
using System.Threading.Tasks;
using Xunit;
public class TestClass {{
[Fact]
public async Task TestMethod() {{
var task = Task.FromResult(42);
await task.[|ConfigureAwait({argumentValue})|];
}}
}}";

await Verify.VerifyAnalyzer(source);
}

[Theory]
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void FailureCase_ValueTask(string argumentValue)
{
var source = @$"
using System.Threading.Tasks;
using Xunit;
public class TestClass {{
[Fact]
public async Task TestMethod() {{
var valueTask = default(ValueTask);
await valueTask.[|ConfigureAwait({argumentValue})|];
}}
}}";

await Verify.VerifyAnalyzer(source);
}

[Theory]
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void FailureCase_ValueTaskOfT(string argumentValue)
{
var source = @$"
using System.Threading.Tasks;
using Xunit;
public class TestClass {{
[Fact]
public async Task TestMethod() {{
var valueTask = default(ValueTask<int>);
await valueTask.[|ConfigureAwait({argumentValue})|];
}}
}}";

await Verify.VerifyAnalyzer(source);
}

[Fact]
public async void IgnoredCase()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class DoNotUseConfigureAwaitFixerTests
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void RemovesConfigureAwait_Async(string argumentValue)
public async void RemovesConfigureAwait_Task_Async(string argumentValue)
{
var before = @$"
using System.Threading.Tasks;
Expand Down Expand Up @@ -39,7 +39,7 @@ public async Task TestMethod() {
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void RemovesConfigureAwait_NonAsync(string argumentValue)
public async void RemovesConfigureAwait_Task_NonAsync(string argumentValue)
{
var before = @$"
using System.Threading.Tasks;
Expand All @@ -65,4 +65,103 @@ public void TestMethod() {

await Verify.VerifyCodeFix(before, after, DoNotUseConfigureAwaitFixer.Key_RemoveConfigureAwait);
}

[Theory]
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void RemovesConfigureAwait_TaskOfT(string argumentValue)
{
var before = @$"
using System.Threading.Tasks;
using Xunit;
public class TestClass {{
[Fact]
public async Task TestMethod() {{
var task = Task.FromResult(42);
await task.[|ConfigureAwait({argumentValue})|];
}}
}}";

var after = @"
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public async Task TestMethod() {
var task = Task.FromResult(42);
await task;
}
}";

await Verify.VerifyCodeFix(before, after, DoNotUseConfigureAwaitFixer.Key_RemoveConfigureAwait);
}

[Theory]
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void RemovesConfigureAwait_ValueTask(string argumentValue)
{
var before = @$"
using System.Threading.Tasks;
using Xunit;
public class TestClass {{
[Fact]
public async Task TestMethod() {{
var valueTask = default(ValueTask);
await valueTask.[|ConfigureAwait({argumentValue})|];
}}
}}";

var after = @"
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public async Task TestMethod() {
var valueTask = default(ValueTask);
await valueTask;
}
}";

await Verify.VerifyCodeFix(before, after, DoNotUseConfigureAwaitFixer.Key_RemoveConfigureAwait);
}

[Theory]
[InlineData("true")]
[InlineData("false")]
[InlineData("1 == 2")]
public async void RemovesConfigureAwait_ValueTaskOfT(string argumentValue)
{
var before = @$"
using System.Threading.Tasks;
using Xunit;
public class TestClass {{
[Fact]
public async Task TestMethod() {{
var valueTask = default(ValueTask<object>);
await valueTask.[|ConfigureAwait({argumentValue})|];
}}
}}";

var after = @"
using System.Threading.Tasks;
using Xunit;
public class TestClass {
[Fact]
public async Task TestMethod() {
var valueTask = default(ValueTask<object>);
await valueTask;
}
}";

await Verify.VerifyCodeFix(before, after, DoNotUseConfigureAwaitFixer.Key_RemoveConfigureAwait);
}
}
6 changes: 6 additions & 0 deletions src/xunit.analyzers/Utility/TypeSymbolFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,18 @@ public static IArrayTypeSymbol ObjectArray(Compilation compilation) =>
public static INamedTypeSymbol? Task(Compilation compilation) =>
compilation.GetTypeByMetadataName("System.Threading.Tasks.Task");

public static INamedTypeSymbol? TaskOfT(Compilation compilation) =>
compilation.GetTypeByMetadataName("System.Threading.Tasks.Task`1");

public static INamedTypeSymbol? TheoryAttribute(Compilation compilation) =>
compilation.GetTypeByMetadataName(Constants.Types.Xunit.TheoryAttribute);

public static INamedTypeSymbol? ValueTask(Compilation compilation) =>
compilation.GetTypeByMetadataName("System.Threading.Tasks.ValueTask");

public static INamedTypeSymbol? ValueTaskOfT(Compilation compilation) =>
compilation.GetTypeByMetadataName("System.Threading.Tasks.ValueTask`1");

public static INamedTypeSymbol Void(Compilation compilation) =>
compilation.GetSpecialType(SpecialType.System_Void);
}
23 changes: 22 additions & 1 deletion src/xunit.analyzers/X1000/DoNotUseConfigureAwait.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ public override void AnalyzeCompilation(
XunitContext xunitContext)
{
var taskType = TypeSymbolFactory.Task(context.Compilation);
var taskOfTType = TypeSymbolFactory.TaskOfT(context.Compilation)?.ConstructUnboundGenericType();
var valueTaskType = TypeSymbolFactory.ValueTask(context.Compilation);
var valueTaskOfTType = TypeSymbolFactory.ValueTaskOfT(context.Compilation)?.ConstructUnboundGenericType();

if (xunitContext.Core.FactAttributeType is null || xunitContext.Core.TheoryAttributeType is null)
return;
Expand All @@ -29,7 +32,25 @@ public override void AnalyzeCompilation(
return;
var methodSymbol = invocation.TargetMethod;
if (methodSymbol.MethodKind != MethodKind.Ordinary || !SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingType, taskType) || methodSymbol.Name != nameof(Task.ConfigureAwait))
if (methodSymbol.MethodKind != MethodKind.Ordinary || methodSymbol.Name != nameof(Task.ConfigureAwait))
return;
bool match;
if (methodSymbol.ContainingType.IsGenericType)
{
var unboundGeneric = methodSymbol.ContainingType.ConstructUnboundGenericType();
match =
SymbolEqualityComparer.Default.Equals(unboundGeneric, taskOfTType) ||
SymbolEqualityComparer.Default.Equals(unboundGeneric, valueTaskOfTType);
}
else
match =
SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingType, taskType) ||
SymbolEqualityComparer.Default.Equals(methodSymbol.ContainingType, valueTaskType);
if (!match)
return;
if (!invocation.IsInTestMethod(xunitContext))
Expand Down

0 comments on commit 3de1575

Please sign in to comment.