Skip to content

Commit

Permalink
AG0012: Fix nested assertions (#154)
Browse files Browse the repository at this point in the history
* Fix code formatting

* Add tests for incorrectly handled cases of nested assertions

* Walk descendant nodes of body statements to identify nested assertions
  • Loading branch information
szaboopeeter authored Jan 19, 2021
1 parent b4e5b96 commit 8a2214a
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 36 deletions.
85 changes: 71 additions & 14 deletions src/Agoda.Analyzers.Test/AgodaCustom/AG0012UnitTests.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
using System.Threading.Tasks;
using Agoda.Analyzers.AgodaCustom;
using Agoda.Analyzers.AgodaCustom;
using Agoda.Analyzers.Test.Helpers;
using Microsoft.CodeAnalysis.Diagnostics;
using NUnit.Framework;
using System.Threading.Tasks;

namespace Agoda.Analyzers.Test.AgodaCustom
{
internal class AG0012UnitTests : DiagnosticVerifier
{
protected override DiagnosticAnalyzer DiagnosticAnalyzer => new AG0012TestMethodMustContainAtLeastOneAssertion();

protected override string DiagnosticId => AG0012TestMethodMustContainAtLeastOneAssertion.DIAGNOSTIC_ID;

[Test]
public async Task AG0012_WithSetupMethod_ShouldNotShowWarning()
{
var code = new CodeDescriptor
{
References = new[] {typeof(TestFixtureAttribute).Assembly},
References = new[] { typeof(TestFixtureAttribute).Assembly },
Code = @"
using NUnit.Framework;
using System;
Expand All @@ -34,16 +34,16 @@ public void This_Is_Valid()
}
}"
};

await VerifyDiagnosticsAsync(code, EmptyDiagnosticResults);
}

[Test]
public async Task AG0012_WithNoAssertion_ShouldShowWarning()
{
var code = new CodeDescriptor
{
References = new[] {typeof(TestFixtureAttribute).Assembly},
References = new[] { typeof(TestFixtureAttribute).Assembly },
Code = @"
using NUnit.Framework;
using System;
Expand All @@ -60,16 +60,16 @@ public void This_Is_NotValid()
}
}"
};

await VerifyDiagnosticsAsync(code, new DiagnosticLocation(9, 29));
}

[Test]
public async Task AG0012_WithNUnitAssertion_ShouldNotShowWarning()
{
var code = new CodeDescriptor
{
References = new[] {typeof(TestFixtureAttribute).Assembly, typeof(Shouldly.Should).Assembly},
References = new[] { typeof(TestFixtureAttribute).Assembly, typeof(Shouldly.Should).Assembly },
Code = @"
using NUnit.Framework;
Expand All @@ -90,14 +90,14 @@ public void This_Is_Valid()
await VerifyDiagnosticsAsync(code, EmptyDiagnosticResults);
}



[Test]
public async Task AG0012_WithShouldlyAssertion_ShouldNotShowWarning()
{
var code = new CodeDescriptor
{
References = new[] {typeof(TestFixtureAttribute).Assembly, typeof(Shouldly.Should).Assembly},
References = new[] { typeof(TestFixtureAttribute).Assembly, typeof(Shouldly.Should).Assembly },
Code = @"
using NUnit.Framework;
using Shouldly;
Expand Down Expand Up @@ -127,5 +127,62 @@ public void This_Is_AlsoValid()

await VerifyDiagnosticsAsync(code, EmptyDiagnosticResults);
}

[Test]
public async Task AG0012_WithNestedAssertions_ShouldNotShowWarning()
{
var code = new CodeDescriptor
{
References = new[] { typeof(TestFixtureAttribute).Assembly, typeof(Shouldly.Should).Assembly },
Code = @"
using NUnit.Framework;
using Shouldly;
using System;
namespace Tests
{
public class TestClass
{
[Test]
public void Assertion_In_Loop_Is_Valid()
{
int[] array = { 1, 2, 3 };
for (int i = 0; i < 3; i++)
{
array[i].ShouldBe(i + 1);
}
}
[Test]
public void Assertion_In_Nested_Loop_Is_Valid()
{
int[] array = { 1, 2, 3 };
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
array[i].ShouldBe(i + 1);
}
}
}
[Test]
public void Assertion_In_Local_Function_Is_Valid()
{
int[] array = { 1, 2, 3 };
helper(array[0]);
void helper(int i)
{
Assert.AreEqual(i, i + 1);
}
}
}
}"
};

await VerifyDiagnosticsAsync(code, EmptyDiagnosticResults);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using System.Collections.Immutable;
using Agoda.Analyzers.Helpers;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Agoda.Analyzers.Helpers;
using Microsoft.CodeAnalysis.Diagnostics;
using System.Collections.Immutable;
using System.Linq;

namespace Agoda.Analyzers.AgodaCustom
Expand All @@ -14,26 +14,26 @@ public class AG0012TestMethodMustContainAtLeastOneAssertion : DiagnosticAnalyzer
public const string DIAGNOSTIC_ID = "AG0012";

private static readonly LocalizableString Title = new LocalizableResourceString(
nameof(CustomRulesResources.AG0012Title),
CustomRulesResources.ResourceManager,
nameof(CustomRulesResources.AG0012Title),
CustomRulesResources.ResourceManager,
typeof(CustomRulesResources));

private static readonly LocalizableString MessageFormat = new LocalizableResourceString(
nameof(CustomRulesResources.AG0012Title),
CustomRulesResources.ResourceManager,
nameof(CustomRulesResources.AG0012Title),
CustomRulesResources.ResourceManager,
typeof(CustomRulesResources));
private static readonly LocalizableString Description

private static readonly LocalizableString Description
= DescriptionContentLoader.GetAnalyzerDescription(nameof(AG0012TestMethodMustContainAtLeastOneAssertion));

private static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
DIAGNOSTIC_ID,
Title,
MessageFormat,
DIAGNOSTIC_ID,
Title,
MessageFormat,
AnalyzerCategory.CustomQualityRules,
DiagnosticSeverity.Warning,
AnalyzerConstants.EnabledByDefault,
Description,
DiagnosticSeverity.Warning,
AnalyzerConstants.EnabledByDefault,
Description,
"https://agoda-com.github.io/standards-c-sharp/testing/tests-as-a-specification.html",
WellKnownDiagnosticTags.EditAndContinue);

Expand All @@ -49,7 +49,7 @@ public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.MethodDeclaration);
}

private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
var methodDeclaration = context.Node as MethodDeclarationSyntax;
Expand All @@ -69,8 +69,7 @@ private static void AnalyzeNode(SyntaxNodeAnalysisContext context)
private static bool HasInvokedAssertStaticMethod(MethodDeclarationSyntax methodDeclaration, SyntaxNodeAnalysisContext context)
{
return methodDeclaration.Body.Statements
.OfType<ExpressionStatementSyntax>()
.Select(ess => ess.Expression)
.SelectMany(s => s.DescendantNodesAndSelf())
.OfType<InvocationExpressionSyntax>()
.Select(ies => ies.Expression)
.OfType<MemberAccessExpressionSyntax>()
Expand All @@ -86,8 +85,7 @@ private static bool HasInvokedAssertStaticMethod(MethodDeclarationSyntax methodD
private static bool HasInvokedAssertExtensionMethod(MethodDeclarationSyntax methodDeclaration, SyntaxNodeAnalysisContext context)
{
return methodDeclaration.Body.Statements
.OfType<ExpressionStatementSyntax>()
.Select(ess => ess.Expression)
.SelectMany(s => s.DescendantNodesAndSelf())
.OfType<InvocationExpressionSyntax>()
.Select(ies => ies.Expression)
.OfType<MemberAccessExpressionSyntax>()
Expand Down

0 comments on commit 8a2214a

Please sign in to comment.