Skip to content

Commit 72c5810

Browse files
authored
add support for xunit SetAsserts Contains (#234)
1 parent 2217761 commit 72c5810

File tree

5 files changed

+57
-4
lines changed

5 files changed

+57
-4
lines changed

src/FluentAssertions.Analyzers.Tests/DiagnosticVerifier.cs

+1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static DiagnosticVerifier()
3939
typeof(AssertionScope), // FluentAssertions.Core
4040
typeof(AssertionExtensions), // FluentAssertions
4141
typeof(HttpRequestMessage), // System.Net.Http
42+
typeof(ImmutableArray), // System.Collections.Immutable
4243
typeof(Microsoft.VisualStudio.TestTools.UnitTesting.Assert), // MsTest
4344
typeof(XunitAssert), // Xunit
4445
}.Select(type => type.GetTypeInfo().Assembly.Location)

src/FluentAssertions.Analyzers.Tests/GenerateCode.cs

+1
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ public static string GenericIListExpressionBodyAssertion(string assertion) => Ge
225225
public static string XunitAssertion(string methodArguments, string assertion) => new StringBuilder()
226226
.AppendLine("using System;")
227227
.AppendLine("using System.Collections.Generic;")
228+
.AppendLine("using System.Collections.Immutable;")
228229
.AppendLine("using System.Text.RegularExpressions;")
229230
.AppendLine("using FluentAssertions;")
230231
.AppendLine("using FluentAssertions.Extensions;")

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

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

5-
using XunitAssert = Xunit.Assert;
6-
75
namespace FluentAssertions.Analyzers.Tests.Tips
86
{
97
[TestClass]
@@ -368,6 +366,36 @@ public void AssertStringContains_TestAnalyzer(string assertion) =>
368366
public void AssertStringContains_TestCodeFix(string oldAssertion, string newAssertion)
369367
=> VerifyCSharpFix<AssertContainsCodeFix, AssertContainsAnalyzer>("string actual, string expected", oldAssertion, newAssertion);
370368

369+
[DataTestMethod]
370+
[DataRow("Assert.Contains(expected, actual);", "ISet<string> actual, string expected")]
371+
[DataRow("Assert.Contains(expected, actual);", "IReadOnlySet<string> actual, string expected")]
372+
[DataRow("Assert.Contains(expected, actual);", "HashSet<string> actual, string expected")]
373+
[DataRow("Assert.Contains(expected, actual);", "ImmutableHashSet<string> actual, string expected")]
374+
[Implemented]
375+
public void AssertSetContains_TestAnalyzer(string assertion, string arguments) =>
376+
VerifyCSharpDiagnostic<AssertContainsAnalyzer>(arguments, assertion);
377+
378+
[DataTestMethod]
379+
[DataRow(
380+
/* oldAssertion: */ "Assert.Contains(expected, actual);",
381+
/* newAssertion: */ "actual.Should().Contain(expected);",
382+
/* arguments: */ "ISet<string> actual, string expected")]
383+
[DataRow(
384+
/* oldAssertion: */ "Assert.Contains(expected, actual);",
385+
/* newAssertion: */ "actual.Should().Contain(expected);",
386+
/* arguments: */ "IReadOnlySet<string> actual, string expected")]
387+
[DataRow(
388+
/* oldAssertion: */ "Assert.Contains(expected, actual);",
389+
/* newAssertion: */ "actual.Should().Contain(expected);",
390+
/* arguments: */ "HashSet<string> actual, string expected")]
391+
[DataRow(
392+
/* oldAssertion: */ "Assert.Contains(expected, actual);",
393+
/* newAssertion: */ "actual.Should().Contain(expected);",
394+
/* arguments: */ "ImmutableHashSet<string> actual, string expected")]
395+
[Implemented]
396+
public void AssertSetContains_TestCodeFix(string oldAssertion, string newAssertion, string arguments)
397+
=> VerifyCSharpFix<AssertContainsCodeFix, AssertContainsAnalyzer>(arguments, oldAssertion, newAssertion);
398+
371399
[DataTestMethod]
372400
[DataRow("Assert.DoesNotContain(expected, actual);")]
373401
[Implemented]
@@ -494,7 +522,7 @@ public void AssertStartsWith_TestCodeFix(string oldAssertion, string newAssertio
494522
Message = message,
495523
Locations = new DiagnosticResultLocation[]
496524
{
497-
new("Test0.cs", 14, 13)
525+
new("Test0.cs", 15, 13)
498526
},
499527
Severity = DiagnosticSeverity.Info
500528
});

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

+18-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ public class AssertContainsAnalyzer : XunitAnalyzer
2121

2222
protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors => new FluentAssertionsCSharpSyntaxVisitor[]
2323
{
24-
new AssertContainsStringSyntaxVisitor()
24+
new AssertContainsStringSyntaxVisitor(),
25+
new AssertContainsSetSyntaxVisitor()
2526
};
2627

2728
//public static void Contains(string expectedSubstring, string? actualString)
@@ -35,6 +36,21 @@ public AssertContainsStringSyntaxVisitor() : base(
3536
{
3637
}
3738
}
39+
40+
//public static void Contains<T>(T expected, ISet<T> actual)
41+
//public static void Contains<T>(T expected, IReadOnlySet<T> actual)
42+
//public static void Contains<T>(T expected, HashSet<T> actual)
43+
//public static void Contains<T>(T expected, ImmutableHashSet<T> actual)
44+
public class AssertContainsSetSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
45+
{
46+
public AssertContainsSetSyntaxVisitor() : base(
47+
MemberValidator.ArgumentsMatch("Contains",
48+
ArgumentValidator.Exists(),
49+
ArgumentValidator.IsTypeOrConstructedFromTypeOrImplementsType(SpecialType.System_Collections_IEnumerable))
50+
)
51+
{
52+
}
53+
}
3854
}
3955

4056
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertContainsCodeFix)), Shared]
@@ -49,6 +65,7 @@ protected override ExpressionSyntax GetNewExpression(
4965
switch (properties.VisitorName)
5066
{
5167
case nameof(AssertContainsAnalyzer.AssertContainsStringSyntaxVisitor):
68+
case nameof(AssertContainsAnalyzer.AssertContainsSetSyntaxVisitor):
5269
return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "Contains", "Contain");
5370
default:
5471
throw new System.InvalidOperationException($"Invalid visitor name - {properties.VisitorName}");

src/FluentAssertions.Analyzers/Utilities/ArgumentValidator.cs

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using FluentAssertions.Analyzers.Utilities;
12
using Microsoft.CodeAnalysis;
23
using Microsoft.CodeAnalysis.CSharp;
34
using Microsoft.CodeAnalysis.CSharp.Syntax;
@@ -11,6 +12,11 @@ public static ArgumentPredicate IsIdentifier()
1112
=> (argument, semanticModel) => argument.Expression.IsKind(SyntaxKind.IdentifierName);
1213
public static ArgumentPredicate IsType(Func<SemanticModel, INamedTypeSymbol> typeSelector)
1314
=> (argument, semanticModel) => semanticModel.GetTypeInfo(argument.Expression).Type?.Equals(typeSelector(semanticModel), SymbolEqualityComparer.Default) ?? false;
15+
public static ArgumentPredicate IsTypeOrConstructedFromTypeOrImplementsType(SpecialType specialType)
16+
=> (argument, semanticModel) => semanticModel.GetTypeInfo(argument.Expression).Type?.IsTypeOrConstructedFromTypeOrImplementsType(specialType) ?? false;
17+
public static ArgumentPredicate Exists() {
18+
return (argument, semanticModel) => true;
19+
}
1420
public static ArgumentPredicate IsAnyType(params Func<SemanticModel, INamedTypeSymbol>[] typeSelectors)
1521
=> (argument, semanticModel) => Array.Exists(typeSelectors, typeSelector => IsType(typeSelector)(argument, semanticModel));
1622
public static ArgumentPredicate IsNull()

0 commit comments

Comments
 (0)