Skip to content

Commit 7c2036d

Browse files
authored
feat: verify assertion type and module (#186)
* reproduce issue #163 * update test * remove unused ShouldAnalyzeMethod * verify assertion type and module
1 parent e059c03 commit 7c2036d

File tree

6 files changed

+58
-51
lines changed

6 files changed

+58
-51
lines changed

src/FluentAssertions.Analyzers.Tests/DiagnosticVerifier.cs

+7
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,13 @@ public static void VerifyCSharpDiagnosticUsingAllAnalyzers(string source, params
450450
VerifyDiagnosticResults(diagnostics, analyzers, expected);
451451
}
452452

453+
public static void VerifyCSharpDiagnosticUsingAllAnalyzers(string[] sources, params DiagnosticResult[] expected)
454+
{
455+
var analyzers = CreateAllAnalyzers();
456+
var diagnostics = GetSortedDiagnostics(sources, LanguageNames.CSharp, analyzers);
457+
VerifyDiagnosticResults(diagnostics, analyzers, expected);
458+
}
459+
453460
/// <summary>
454461
/// General method that gets a collection of actual diagnostics found in the source after the analyzer is run,
455462
/// then verifies each of them.

src/FluentAssertions.Analyzers.Tests/Tips/SanityTests.cs

+38-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
using Microsoft.VisualStudio.TestTools.UnitTesting;
1+
using FluentAssertions.Analyzers.Xunit;
2+
using Microsoft.CodeAnalysis;
3+
using Microsoft.CodeAnalysis.CSharp;
4+
using Microsoft.CodeAnalysis.CSharp.Syntax;
5+
using Microsoft.CodeAnalysis.Text;
6+
using Microsoft.VisualStudio.TestTools.UnitTesting;
27

38
namespace FluentAssertions.Analyzers.Tests
49
{
@@ -302,5 +307,37 @@ public static void Main()
302307

303308
DiagnosticVerifier.VerifyCSharpFix<AssertAreEqualCodeFix, AssertAreEqualAnalyzer>(oldSource, newSource);
304309
}
310+
311+
[TestMethod]
312+
[Implemented(Reason = "https://github.com/fluentassertions/fluentassertions.analyzers/issues/163")]
313+
public void GlobalUsingsWithAssert()
314+
{
315+
const string globalUsings = @"
316+
global using Xunit;
317+
global using FluentAssertions;
318+
global using FluentAssertions.Extensions;";
319+
const string source = @"
320+
public class TestClass
321+
{
322+
public static void Main()
323+
{
324+
var x = false;
325+
Assert.True(x);
326+
TestClass.True(x);
327+
}
328+
329+
public static void True(bool input)
330+
{
331+
}
332+
}";
333+
334+
DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(new[] { source, globalUsings }, new DiagnosticResult()
335+
{
336+
Id = AssertTrueAnalyzer.DiagnosticId,
337+
Message = AssertTrueAnalyzer.Message,
338+
Severity = DiagnosticSeverity.Info,
339+
Locations = new[] { new DiagnosticResultLocation("Test0.cs", 7, 9) }
340+
});
341+
}
305342
}
306343
}

src/FluentAssertions.Analyzers.Tests/Tips/XunitTests.cs

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using Microsoft.VisualStudio.TestTools.UnitTesting;
33
using FluentAssertions.Analyzers.Xunit;
44

5+
using XunitAssert = Xunit.Assert;
6+
57
namespace FluentAssertions.Analyzers.Tests.Tips
68
{
79
[TestClass]

src/FluentAssertions.Analyzers/Tips/MsTest/MsTestBase.cs

+4-5
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,22 @@ namespace FluentAssertions.Analyzers
77
{
88
public abstract class MsTestAnalyzer : TestingLibraryAnalyzerBase
99
{
10-
private static readonly string MsTestNamespace = "Microsoft.VisualStudio.TestTools.UnitTesting";
11-
protected override string TestingLibraryNamespace => MsTestNamespace;
10+
protected override string TestingLibraryModule => "Microsoft.VisualStudio.TestPlatform.TestFramework";
1211
}
1312

1413
public abstract class MsTestAssertAnalyzer : MsTestAnalyzer
1514
{
16-
protected override bool ShouldAnalyzeVariableType(INamedTypeSymbol type, SemanticModel semanticModel) => type.Name == "Assert";
15+
override protected string TestingLibraryAssertionType => "Assert";
1716
}
1817

1918
public abstract class MsTestStringAssertAnalyzer : MsTestAnalyzer
2019
{
21-
protected override bool ShouldAnalyzeVariableType(INamedTypeSymbol type, SemanticModel semanticModel) => type.Name == "StringAssert";
20+
override protected string TestingLibraryAssertionType => "StringAssert";
2221
}
2322

2423
public abstract class MsTestCollectionAssertAnalyzer : MsTestAnalyzer
2524
{
26-
protected override bool ShouldAnalyzeVariableType(INamedTypeSymbol type, SemanticModel semanticModel) => type.Name == "CollectionAssert";
25+
override protected string TestingLibraryAssertionType => "CollectionAssert";
2726
}
2827

2928
public abstract class MsTestAssertCodeFixProvider : TestingLibraryCodeFixBase

src/FluentAssertions.Analyzers/Tips/Xunit/XunitBase.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ namespace FluentAssertions.Analyzers.Xunit
66
{
77
public abstract class XunitAnalyzer : TestingLibraryAnalyzerBase
88
{
9-
private static readonly string XunitNamespace = "Xunit";
10-
protected override string TestingLibraryNamespace => XunitNamespace;
9+
protected override string TestingLibraryModule => "xunit.assert";
10+
protected override string TestingLibraryAssertionType => "Assert";
1111

1212
protected override bool ShouldAnalyzeVariableType(INamedTypeSymbol type, SemanticModel semanticModel) => type.Name == "Assert";
1313
}

src/FluentAssertions.Analyzers/Utilities/FluentAssertionsAnalyzer.cs

+5-43
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Collections.Immutable;
8-
using System.Linq;
9-
using SF = Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
108

119
namespace FluentAssertions.Analyzers
1210
{
@@ -46,8 +44,6 @@ private void AnalyzeExpressionStatementSyntax(SyntaxNodeAnalysisContext context)
4644
}
4745
}
4846

49-
protected virtual bool ShouldAnalyzeMethod(MethodDeclarationSyntax method) => true;
50-
5147
protected virtual bool ShouldAnalyzeVariableType(INamedTypeSymbol type, SemanticModel semanticModel) => true;
5248

5349
protected virtual Diagnostic AnalyzeExpression(ExpressionSyntax expression, SemanticModel semanticModel)
@@ -77,7 +73,7 @@ protected virtual Diagnostic CreateDiagnostic(TCSharpSyntaxVisitor visitor, Expr
7773
{
7874
var properties = visitor.ToDiagnosticProperties()
7975
.Add(Constants.DiagnosticProperties.Title, Title);
80-
var newRule = new DiagnosticDescriptor(Rule.Id, Rule.Title, Rule.MessageFormat, Rule.Category, Rule.DefaultSeverity, true,
76+
var newRule = new DiagnosticDescriptor(Rule.Id, Rule.Title, Rule.MessageFormat, Rule.Category, Rule.DefaultSeverity, true,
8177
helpLinkUri: properties.GetValueOrDefault(Constants.DiagnosticProperties.HelpLink));
8278
return Diagnostic.Create(
8379
descriptor: newRule,
@@ -105,44 +101,10 @@ public abstract class FluentAssertionsAnalyzer : FluentAssertionsAnalyzer<Fluent
105101

106102
public abstract class TestingLibraryAnalyzerBase : FluentAssertionsAnalyzer
107103
{
108-
protected abstract string TestingLibraryNamespace { get; }
109-
110-
protected override bool ShouldAnalyzeMethod(MethodDeclarationSyntax method)
111-
{
112-
var compilation = method.FirstAncestorOrSelf<CompilationUnitSyntax>();
113-
114-
if (compilation == null) return false;
115-
116-
foreach (var @using in compilation.Usings)
117-
{
118-
if (@using.Name.NormalizeWhitespace().ToString().Equals(TestingLibraryNamespace)) return true;
119-
}
120-
121-
var parentNamespace = method.FirstAncestorOrSelf<NamespaceDeclarationSyntax>();
122-
if (parentNamespace != null)
123-
{
124-
var namespaces = new List<NamespaceDeclarationSyntax>();
125-
while(parentNamespace != null)
126-
{
127-
namespaces.Add(parentNamespace);
128-
parentNamespace = parentNamespace.Parent as NamespaceDeclarationSyntax;
129-
}
130-
namespaces.Reverse();
131-
132-
for (int i = 0; i < namespaces.Count; i++)
133-
{
134-
var baseNamespace = string.Join(".", namespaces.Take(i+1).Select(ns => ns.Name));
135-
foreach (var @using in namespaces[i].Usings)
136-
{
137-
if (@using.Name.NormalizeWhitespace().ToString().Equals(TestingLibraryNamespace)) return true;
138-
139-
var fullUsing = SF.ParseName($"{baseNamespace}.{@using.Name}").NormalizeWhitespace().ToString();
140-
if (fullUsing.Equals(TestingLibraryNamespace)) return true;
141-
}
142-
}
143-
}
104+
protected abstract string TestingLibraryModule { get; }
105+
protected abstract string TestingLibraryAssertionType { get; }
144106

145-
return false;
146-
}
107+
protected override bool ShouldAnalyzeVariableType(INamedTypeSymbol type, SemanticModel semanticModel)
108+
=> type.Name == TestingLibraryAssertionType && type.ContainingModule.Name == TestingLibraryModule + ".dll";
147109
}
148110
}

0 commit comments

Comments
 (0)