Skip to content

Commit

Permalink
Add tests to CodeFixProviderSnippetTest
Browse files Browse the repository at this point in the history
  • Loading branch information
martin-strecker-sonarsource committed Jun 14, 2024
1 parent 2bbae99 commit 2ad9633
Showing 1 changed file with 85 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,88 @@ public void VerifyCodeFix_Snippet()
var verifier = new VerifierBuilder
{
Analyzers = [() => new TestRule([SyntaxKind.ClassDeclaration])],
CodeFix = () => new TestRuleCodeFix(async (document, node) =>
document.WithSyntaxRoot(
(await node.SyntaxTree.GetRootAsync()).ReplaceNode(node, node is ClassDeclarationSyntax classDeclaration
? classDeclaration.WithIdentifier(SyntaxFactory.Identifier("Changed").WithTriviaFrom(classDeclaration.Identifier))
: node))),
CodeFix = () => new TestRuleCodeFix<ClassDeclarationSyntax>((root, node) =>
root.ReplaceNode(node, node.WithIdentifier(SyntaxFactory.Identifier("Changed").WithTriviaFrom(node.Identifier)))),
}
.AddSnippet("""
class C { }
""")
.WithCodeFixedSnippet(
"""
.WithCodeFixedSnippet("""
class Changed { }
""");
Action a = () => verifier.VerifyCodeFix();
a.Should().NotThrow();
}

[TestMethod]
public void VerifyCodeFix_Snippet_Fail()
{
var verifier = new VerifierBuilder
{
Analyzers = [() => new TestRule([SyntaxKind.ClassDeclaration])],
CodeFix = () => new TestRuleCodeFix<ClassDeclarationSyntax>((root, node) =>
root.ReplaceNode(node, node.WithIdentifier(SyntaxFactory.Identifier("ActualChange").WithTriviaFrom(node.Identifier)))),
}
.AddSnippet("""
class C { }
""")
.WithCodeFixedSnippet("""
class ExpectedChange { }
""");
Action a = () => verifier.VerifyCodeFix();
a.Should().Throw<AssertFailedException>().WithMessage(
"""Expected ActualCodeWithReplacedComments().ToUnixLineEndings() to be "class ExpectedChange { }" with a length of 24 """ +
"""because VerifyWhileDocumentChanges updates the document until all issues are fixed, even if the fix itself creates a new issue again. Language: CSharp7, """ +
"""but "class ActualChange { }" has a length of 22, differs near "Act" (index 6).""");
}

[TestMethod]
public void VerifyCodeFix_Snippet_Fail_WithNoncompliantComment()
{
var verifier = new VerifierBuilder
{
Analyzers = [() => new TestRule([SyntaxKind.ClassDeclaration])],
CodeFix = () => new TestRuleCodeFix<ClassDeclarationSyntax>((root, node) =>
root.ReplaceNode(node, node.WithIdentifier(SyntaxFactory.Identifier("ActualChange").WithTriviaFrom(node.Identifier)))),
}
.AddSnippet("""
class C { } // Noncompliant
""")
.WithCodeFixedSnippet("""
class ExpectedChange { } // Fixed
""");
Action a = () => verifier.VerifyCodeFix();
a.Should().Throw<AssertFailedException>().WithMessage(
"""Expected ActualCodeWithReplacedComments().ToUnixLineEndings() to be "class ExpectedChange { } // Fixed" with a length of 33 """ +
"""because VerifyWhileDocumentChanges updates the document until all issues are fixed, even if the fix itself creates a new issue again. Language: CSharp7, """ +
"""but "class ActualChange { } // Fixed" has a length of 31, differs near "Act" (index 6).""");
}

[DataTestMethod]
[DataRow(true)]
[DataRow(false)]
public void VerifyCodeFix_Snippet_MultipleIssues(bool withFixAllProvider)
{
var verifier = new VerifierBuilder
{
Analyzers = [() => new TestRule([SyntaxKind.ClassDeclaration], x => x is ClassDeclarationSyntax c && c.Identifier.ValueText.Length == 1)],
CodeFix = () => new TestRuleCodeFix<ClassDeclarationSyntax>(withFixAllProvider, (root, node) =>
root.ReplaceNode(node, node.WithIdentifier(SyntaxFactory.Identifier($"{node.Identifier.ValueText}Changed").WithTriviaFrom(node.Identifier)))),
}
.AddSnippet("""
class A { } // Noncompliant
class B { } // Noncompliant
class C { } // Noncompliant
""")
.WithCodeFixedSnippet("""
class AChanged { } // Fixed
class BChanged { } // Fixed
class CChanged { } // Fixed
""");
Action a = () => verifier.VerifyCodeFix();
a.Should().NotThrow();
}

[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class TestRule : SonarDiagnosticAnalyzer
{
Expand All @@ -78,27 +143,29 @@ protected override void Initialize(SonarAnalysisContext context) =>
{
c.ReportIssue(rule, c.Context.Node);
}
}, [..RegisterSyntaxKinds]);
}, RegisterSyntaxKinds);
}

[ExportCodeFixProvider(LanguageNames.CSharp)]
public class TestRuleCodeFix : SonarCodeFix
public class TestRuleCodeFix<TSyntax>(bool withFixAllProvider, Func<SyntaxNode, TSyntax, SyntaxNode> createChangedRoot) : SonarCodeFix where TSyntax : SyntaxNode
{
public override ImmutableArray<string> FixableDiagnosticIds => [TestRule.DiagnosticId];

public Func<Document, SyntaxNode, Task<Document>> CreateChangedDocument { get; }
public TestRuleCodeFix(Func<SyntaxNode, TSyntax, SyntaxNode> createChangedRoot) : this(true, createChangedRoot) { }

public TestRuleCodeFix(Func<Document, SyntaxNode, Task<Document>> createChangedDocument)
{
CreateChangedDocument = createChangedDocument;
}
public override FixAllProvider GetFixAllProvider() => withFixAllProvider
? base.GetFixAllProvider()
: null;

protected override Task RegisterCodeFixesAsync(SyntaxNode root, SonarCodeFixContext context)
{
context.RegisterCodeFix("TestTitle", async x => await CreateChangedDocument(
context.Document,
(await context.Document.GetSyntaxRootAsync(x)).FindNode(context.Span)),
context.Diagnostics);
context.RegisterCodeFix("TestTitle", async x =>
{
var root = await context.Document.GetSyntaxRootAsync(x);
var node = (TSyntax)root.FindNode(context.Span);
var newRoot = createChangedRoot(root, node);
return context.Document.WithSyntaxRoot(newRoot);
}, context.Diagnostics);
return Task.CompletedTask;
}
}
Expand Down

0 comments on commit 2ad9633

Please sign in to comment.