Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
61 changes: 36 additions & 25 deletions TUnit.Analyzers.CodeFixers/TwoPhase/XUnitTwoPhaseAnalyzer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -865,38 +865,49 @@ protected override bool ShouldRemoveAttribute(AttributeSyntax node)
return conversion;
}

private static readonly Dictionary<string, string> _xUnitFactAndTheoryToTUnitArguments = new()
{
{ "Skip", "Skip" },
{ "DisplayName", "DisplayName" },
{ "Timeout", "Timeout" },
};

private AttributeConversion ConvertTestAttribute(AttributeSyntax node)
{
// Check for Skip argument: [Fact(Skip = "reason")] or [Theory(Skip = "reason")]
var skipArg = node.ArgumentList?.Arguments
.FirstOrDefault(a => a.NameEquals?.Name.Identifier.ValueText == "Skip");
var result = new AttributeConversion
{
NewAttributeName = "Test",
NewArgumentList = "", // Remove any arguments
OriginalText = node.ToString(),
AdditionalAttributes = node.ArgumentList is null ? null : []
};

if (skipArg != null)
if (node.ArgumentList is null)
{
// Extract the skip reason and create additional Skip attribute
var skipReason = skipArg.Expression.ToString();
return new AttributeConversion
{
NewAttributeName = "Test",
NewArgumentList = "", // Remove the Skip argument
OriginalText = node.ToString(),
AdditionalAttributes = new List<AdditionalAttribute>
{
new AdditionalAttribute
{
Name = "Skip",
Arguments = $"({skipReason})"
}
}
};
return result;
}

return new AttributeConversion
foreach (var argument in node.ArgumentList.Arguments)
{
NewAttributeName = "Test",
NewArgumentList = "", // Remove any arguments
OriginalText = node.ToString()
};
if (argument.NameEquals is null)
{
continue;
}

if (!_xUnitFactAndTheoryToTUnitArguments.TryGetValue(argument.NameEquals.Name.Identifier.ValueText, out var argumentName))
{
continue;
}

var argumentValue = argument.Expression.ToString();
result.AdditionalAttributes!.Add(new AdditionalAttribute
{
Name = argumentName,
Arguments = $"({argumentValue})"
});
}

return result;
}

private AttributeConversion? ConvertCollection(AttributeSyntax node)
Expand Down
72 changes: 72 additions & 0 deletions TUnit.Analyzers.Tests/XUnitMigrationAnalyzerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,78 @@ public void MyTest()
);
}

[Test]
[Arguments("Fact")]
[Arguments("Theory")]
[Arguments("Xunit.Fact")]
[Arguments("Xunit.Theory")]
public async Task DisplayNamed_Test_Attributes_Can_Be_Fixed(string attribute)
{
await CodeFixer
.VerifyCodeFixAsync(
$$"""
{|#0:using Xunit;

public class MyClass
{
[{{attribute}}(DisplayName = "Description")]
public void MyTest()
{
}
}|}
""",
Verifier.Diagnostic(Rules.XunitMigration).WithLocation(0),
$$"""

public class MyClass
{
[Test]
[DisplayName("Description")]
public void MyTest()
{
}
}
""",
ConfigureXUnitTest
);
}

[Test]
[Arguments("Fact")]
[Arguments("Theory")]
[Arguments("Xunit.Fact")]
[Arguments("Xunit.Theory")]
public async Task Timeout_Test_Attributes_Can_Be_Fixed(string attribute)
{
await CodeFixer
.VerifyCodeFixAsync(
$$"""
{|#0:using Xunit;

public class MyClass
{
[{{attribute}}(Timeout = 3600)]
public void MyTest()
{
}
}|}
""",
Verifier.Diagnostic(Rules.XunitMigration).WithLocation(0),
$$"""

public class MyClass
{
[Test]
[Timeout(3600)]
public void MyTest()
{
}
}
""",
ConfigureXUnitTest
);
}

[Test]
public async Task Collection_Attributes_Can_Be_Fixed()
{
Expand Down
Loading