Skip to content

add support for xunit SetAsserts Contains #234

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
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
1 change: 1 addition & 0 deletions src/FluentAssertions.Analyzers.Tests/DiagnosticVerifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ static DiagnosticVerifier()
typeof(AssertionScope), // FluentAssertions.Core
typeof(AssertionExtensions), // FluentAssertions
typeof(HttpRequestMessage), // System.Net.Http
typeof(ImmutableArray), // System.Collections.Immutable
typeof(Microsoft.VisualStudio.TestTools.UnitTesting.Assert), // MsTest
typeof(XunitAssert), // Xunit
}.Select(type => type.GetTypeInfo().Assembly.Location)
Expand Down
1 change: 1 addition & 0 deletions src/FluentAssertions.Analyzers.Tests/GenerateCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ public static string GenericIListExpressionBodyAssertion(string assertion) => Ge
public static string XunitAssertion(string methodArguments, string assertion) => new StringBuilder()
.AppendLine("using System;")
.AppendLine("using System.Collections.Generic;")
.AppendLine("using System.Collections.Immutable;")
.AppendLine("using System.Text.RegularExpressions;")
.AppendLine("using FluentAssertions;")
.AppendLine("using FluentAssertions.Extensions;")
Expand Down
34 changes: 31 additions & 3 deletions src/FluentAssertions.Analyzers.Tests/Tips/XunitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using FluentAssertions.Analyzers.Xunit;

using XunitAssert = Xunit.Assert;

namespace FluentAssertions.Analyzers.Tests.Tips
{
[TestClass]
Expand Down Expand Up @@ -368,6 +366,36 @@ public void AssertStringContains_TestAnalyzer(string assertion) =>
public void AssertStringContains_TestCodeFix(string oldAssertion, string newAssertion)
=> VerifyCSharpFix<AssertContainsCodeFix, AssertContainsAnalyzer>("string actual, string expected", oldAssertion, newAssertion);

[DataTestMethod]
[DataRow("Assert.Contains(expected, actual);", "ISet<string> actual, string expected")]
[DataRow("Assert.Contains(expected, actual);", "IReadOnlySet<string> actual, string expected")]
[DataRow("Assert.Contains(expected, actual);", "HashSet<string> actual, string expected")]
[DataRow("Assert.Contains(expected, actual);", "ImmutableHashSet<string> actual, string expected")]
[Implemented]
public void AssertSetContains_TestAnalyzer(string assertion, string arguments) =>
VerifyCSharpDiagnostic<AssertContainsAnalyzer>(arguments, assertion);

[DataTestMethod]
[DataRow(
/* oldAssertion: */ "Assert.Contains(expected, actual);",
/* newAssertion: */ "actual.Should().Contain(expected);",
/* arguments: */ "ISet<string> actual, string expected")]
[DataRow(
/* oldAssertion: */ "Assert.Contains(expected, actual);",
/* newAssertion: */ "actual.Should().Contain(expected);",
/* arguments: */ "IReadOnlySet<string> actual, string expected")]
[DataRow(
/* oldAssertion: */ "Assert.Contains(expected, actual);",
/* newAssertion: */ "actual.Should().Contain(expected);",
/* arguments: */ "HashSet<string> actual, string expected")]
[DataRow(
/* oldAssertion: */ "Assert.Contains(expected, actual);",
/* newAssertion: */ "actual.Should().Contain(expected);",
/* arguments: */ "ImmutableHashSet<string> actual, string expected")]
[Implemented]
public void AssertSetContains_TestCodeFix(string oldAssertion, string newAssertion, string arguments)
=> VerifyCSharpFix<AssertContainsCodeFix, AssertContainsAnalyzer>(arguments, oldAssertion, newAssertion);

[DataTestMethod]
[DataRow("Assert.DoesNotContain(expected, actual);")]
[Implemented]
Expand Down Expand Up @@ -494,7 +522,7 @@ public void AssertStartsWith_TestCodeFix(string oldAssertion, string newAssertio
Message = message,
Locations = new DiagnosticResultLocation[]
{
new("Test0.cs", 14, 13)
new("Test0.cs", 15, 13)
},
Severity = DiagnosticSeverity.Info
});
Expand Down
19 changes: 18 additions & 1 deletion src/FluentAssertions.Analyzers/Tips/Xunit/AssertContains.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public class AssertContainsAnalyzer : XunitAnalyzer

protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors => new FluentAssertionsCSharpSyntaxVisitor[]
{
new AssertContainsStringSyntaxVisitor()
new AssertContainsStringSyntaxVisitor(),
new AssertContainsSetSyntaxVisitor()
};

//public static void Contains(string expectedSubstring, string? actualString)
Expand All @@ -35,6 +36,21 @@ public AssertContainsStringSyntaxVisitor() : base(
{
}
}

//public static void Contains<T>(T expected, ISet<T> actual)
//public static void Contains<T>(T expected, IReadOnlySet<T> actual)
//public static void Contains<T>(T expected, HashSet<T> actual)
//public static void Contains<T>(T expected, ImmutableHashSet<T> actual)
public class AssertContainsSetSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
{
public AssertContainsSetSyntaxVisitor() : base(
MemberValidator.ArgumentsMatch("Contains",
ArgumentValidator.Exists(),
ArgumentValidator.IsTypeOrConstructedFromTypeOrImplementsType(SpecialType.System_Collections_IEnumerable))
)
{
}
}
}

[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(AssertContainsCodeFix)), Shared]
Expand All @@ -49,6 +65,7 @@ protected override ExpressionSyntax GetNewExpression(
switch (properties.VisitorName)
{
case nameof(AssertContainsAnalyzer.AssertContainsStringSyntaxVisitor):
case nameof(AssertContainsAnalyzer.AssertContainsSetSyntaxVisitor):
return RenameMethodAndReorderActualExpectedAndReplaceWithSubjectShould(expression, "Contains", "Contain");
default:
throw new System.InvalidOperationException($"Invalid visitor name - {properties.VisitorName}");
Expand Down
6 changes: 6 additions & 0 deletions src/FluentAssertions.Analyzers/Utilities/ArgumentValidator.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using FluentAssertions.Analyzers.Utilities;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
Expand All @@ -11,6 +12,11 @@ public static ArgumentPredicate IsIdentifier()
=> (argument, semanticModel) => argument.Expression.IsKind(SyntaxKind.IdentifierName);
public static ArgumentPredicate IsType(Func<SemanticModel, INamedTypeSymbol> typeSelector)
=> (argument, semanticModel) => semanticModel.GetTypeInfo(argument.Expression).Type?.Equals(typeSelector(semanticModel), SymbolEqualityComparer.Default) ?? false;
public static ArgumentPredicate IsTypeOrConstructedFromTypeOrImplementsType(SpecialType specialType)
=> (argument, semanticModel) => semanticModel.GetTypeInfo(argument.Expression).Type?.IsTypeOrConstructedFromTypeOrImplementsType(specialType) ?? false;
public static ArgumentPredicate Exists() {
return (argument, semanticModel) => true;
}
public static ArgumentPredicate IsAnyType(params Func<SemanticModel, INamedTypeSymbol>[] typeSelectors)
=> (argument, semanticModel) => Array.Exists(typeSelectors, typeSelector => IsType(typeSelector)(argument, semanticModel));
public static ArgumentPredicate IsNull()
Expand Down