Skip to content

Commit

Permalink
Feature/string assertions (#23)
Browse files Browse the repository at this point in the history
* added string assertion tests

* added string analyzers
  • Loading branch information
Meir017 authored Feb 11, 2018
1 parent 4f1c7b7 commit dcb2c69
Show file tree
Hide file tree
Showing 45 changed files with 758 additions and 52 deletions.
27 changes: 24 additions & 3 deletions src/FluentAssertions.Analyzers.Tests/GenerateCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public static string EnumerableExpressionBodyAssertion(string assertion) => Enum
.AppendLine("{")
.AppendLine(" public class TestClass")
.AppendLine(" {")
.AppendLine($" public void TestMethod(IList<TestComplexClass> actual, IList<TestComplexClass> expected, IList<TestComplexClass> unexpected, TestComplexClass expectedItem, TestComplexClass unexpectedItem, int k)")
.AppendLine(" public void TestMethod(IList<TestComplexClass> actual, IList<TestComplexClass> expected, IList<TestComplexClass> unexpected, TestComplexClass expectedItem, TestComplexClass unexpectedItem, int k)")
.AppendLine(bodyExpression)
.AppendLine(" }")
.AppendLine(" public class TestComplexClass")
Expand All @@ -47,7 +47,7 @@ public static string EnumerableExpressionBodyAssertion(string assertion) => Enum
.AppendLine("{")
.AppendLine(" public class TestClass")
.AppendLine(" {")
.AppendLine($" public void TestMethod(Dictionary<string, TestComplexClass> actual, IDictionary<string, TestComplexClass> expected, IDictionary<string, TestComplexClass> unexpected, string expectedKey, TestComplexClass expectedValue, string unexpectedKey, TestComplexClass unexpectedValue, KeyValuePair<string, TestComplexClass> pair, KeyValuePair<string, TestComplexClass> otherPair)")
.AppendLine(" public void TestMethod(Dictionary<string, TestComplexClass> actual, IDictionary<string, TestComplexClass> expected, IDictionary<string, TestComplexClass> unexpected, string expectedKey, TestComplexClass expectedValue, string unexpectedKey, TestComplexClass unexpectedValue, KeyValuePair<string, TestComplexClass> pair, KeyValuePair<string, TestComplexClass> otherPair)")
.AppendLine(" {")
.AppendLine($" {assertion}")
.AppendLine(" }")
Expand All @@ -70,12 +70,33 @@ public static string EnumerableExpressionBodyAssertion(string assertion) => Enum
.AppendLine("{")
.AppendLine(" class TestClass")
.AppendLine(" {")
.AppendLine($" void TestMethod(int actual, int expected)")
.AppendLine(" void TestMethod(int actual, int expected)")
.AppendLine(" {")
.AppendLine($" {assertion}")
.AppendLine(" }")
.AppendLine(" }")
.AppendLine("}")
.ToString();

public static string StringAssertion(string assertion) => new StringBuilder()
.AppendLine("using System;")
.AppendLine("using FluentAssertions;")
.AppendLine("namespace TestNamespace")
.AppendLine("{")
.AppendLine(" class TestClass")
.AppendLine(" {")
.AppendLine(" void TestMethod(string actual, string expected, int k)")
.AppendLine(" {")
.AppendLine($" {assertion}")
.AppendLine(" }")
.AppendLine(" }")
.AppendLine(" class Program")
.AppendLine(" {")
.AppendLine(" public static void Main()")
.AppendLine(" {")
.AppendLine(" }")
.AppendLine(" }")
.AppendLine("}")
.ToString();
}
}
9 changes: 1 addition & 8 deletions src/FluentAssertions.Analyzers.Tests/Tips/CollectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,7 @@ namespace FluentAssertions.Analyzers.Tests
public class CollectionTests
{
public TestContext TestContext { get; set; }

[AssertionDataTestMethod]
[AssertionDiagnostic("nestedList.Should().NotBeNull({0}).And.ContainSingle().Which.Should().NotBeEmpty();")]
[AssertionDiagnostic("nestedList.Should().NotBeNull().And.ContainSingle().Which.Should().NotBeEmpty({0});")]
[AssertionDiagnostic("nestedList.Should().NotBeNull().And.ContainSingle({0}).Which.Should().NotBeEmpty();")]
[NotImplemented]
public void NoDiagnostics(string assertion) => VerifyCSharpNoDiagnosticsCodeBlock(assertion);


[AssertionDataTestMethod]
[AssertionDiagnostic("actual.Any().Should().BeTrue({0});")]
[AssertionDiagnostic("actual.AsEnumerable().Any().Should().BeTrue({0}).And.ToString();")]
Expand Down
204 changes: 204 additions & 0 deletions src/FluentAssertions.Analyzers.Tests/Tips/StringTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace FluentAssertions.Analyzers.Tests
{
[TestClass]
public class StringTests
{
[AssertionDataTestMethod]
[AssertionDiagnostic("actual.StartsWith(expected).Should().BeTrue({0});")]
[AssertionDiagnostic("actual.ToString().StartsWith(expected).Should().BeTrue({0}).And.ToString();")]
[Implemented]
public void StringShouldStartWith_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldStartWithAnalyzer>(assertion);

[AssertionDataTestMethod]
[AssertionCodeFix(
oldAssertion: "actual.StartsWith(expected).Should().BeTrue({0});",
newAssertion: "actual.Should().StartWith(expected{0});")]
[AssertionCodeFix(
oldAssertion: "actual.ToString().StartsWith(expected).Should().BeTrue({0}).And.ToString();",
newAssertion: "actual.ToString().Should().StartWith(expected{0}).And.ToString();")]
[Implemented]
public void StringShouldStartWith_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldStartWithCodeFix, StringShouldStartWithAnalyzer>(oldAssertion, newAssertion);

[AssertionDataTestMethod]
[AssertionDiagnostic("actual.EndsWith(expected).Should().BeTrue({0});")]
[AssertionDiagnostic("actual.ToString().EndsWith(expected).Should().BeTrue({0}).And.ToString();")]
[Implemented]
public void StringShouldEndWith_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldEndWithAnalyzer>(assertion);

[AssertionDataTestMethod]
[AssertionCodeFix(
oldAssertion: "actual.EndsWith(expected).Should().BeTrue({0});",
newAssertion: "actual.Should().EndWith(expected{0});")]
[AssertionCodeFix(
oldAssertion: "actual.ToString().EndsWith(expected).Should().BeTrue({0}).And.ToString();",
newAssertion: "actual.ToString().Should().EndWith(expected{0}).And.ToString();")]
[Implemented]
public void StringShouldEndWith_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldEndWithCodeFix, StringShouldEndWithAnalyzer>(oldAssertion, newAssertion);

[AssertionDataTestMethod]
[AssertionDiagnostic("actual.Should().NotBeNull().And.NotBeEmpty({0});")]
[AssertionDiagnostic("actual.Should().NotBeNull({0}).And.NotBeEmpty();")]
[AssertionDiagnostic("string.IsNullOrEmpty(actual).Should().BeFalse({0});")]
[AssertionDiagnostic("actual.ToString().Should().NotBeNull().And.NotBeEmpty({0}).And.ToString();")]
[AssertionDiagnostic("actual.ToString().Should().NotBeNull({0}).And.NotBeEmpty().And.ToString();")]
[AssertionDiagnostic("actual.ToString().Should().NotBeEmpty({0}).And.NotBeNull({0}).And.ToString();")]
[AssertionDiagnostic("string.IsNullOrEmpty(actual.ToString()).Should().BeFalse({0}).And.ToString();")]
[Implemented]
public void StringShouldNotBeNullOrEmpty_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldNotBeNullOrEmptyAnalyzer>(assertion);

[AssertionDataTestMethod]
[AssertionCodeFix(
oldAssertion: "actual.Should().NotBeNull({0}).And.NotBeEmpty();",
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "actual.Should().NotBeNull().And.NotBeEmpty({0});",
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "actual.Should().NotBeEmpty({0}).And.NotBeNull();",
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "actual.Should().NotBeEmpty().And.NotBeNull({0});",
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrEmpty(actual).Should().BeFalse({0});",
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "actual.ToString().Should().NotBeNull({0}).And.NotBeEmpty().And.ToString();",
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
[AssertionCodeFix(
oldAssertion: "actual.ToString().Should().NotBeNull().And.NotBeEmpty({0}).And.ToString();",
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
[AssertionCodeFix(
oldAssertion: "actual.ToString().Should().NotBeEmpty({0}).And.NotBeNull().And.ToString();",
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
[AssertionCodeFix(
oldAssertion: "actual.ToString().Should().NotBeEmpty().And.NotBeNull({0}).And.ToString();",
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrEmpty(actual.ToString()).Should().BeFalse({0}).And.ToString();",
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
[Implemented]
public void StringShouldNotBeNullOrEmpty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldNotBeNullOrEmptyCodeFix, StringShouldNotBeNullOrEmptyAnalyzer>(oldAssertion, newAssertion);

[AssertionDataTestMethod]
[AssertionDiagnostic("string.IsNullOrEmpty(actual).Should().BeTrue({0});")]
[AssertionDiagnostic("string.IsNullOrEmpty(actual).Should().BeTrue({0}).And.ToString();")]
[AssertionDiagnostic("string.IsNullOrEmpty(actual.ToString()).Should().BeTrue({0});")]
[AssertionDiagnostic("string.IsNullOrEmpty(actual.ToString()).Should().BeTrue({0}).And.ToString();")]
[Implemented]
public void StringShouldBeNullOrEmpty_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldBeNullOrEmptyAnalyzer>(assertion);

[AssertionDataTestMethod]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrEmpty(actual).Should().BeTrue({0});",
newAssertion: "actual.Should().BeNullOrEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrEmpty(actual).Should().BeTrue({0}).And.ToString();",
newAssertion: "actual.Should().BeNullOrEmpty({0}).And.ToString();")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrEmpty(actual.ToString()).Should().BeTrue({0});",
newAssertion: "actual.ToString().Should().BeNullOrEmpty({0});")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrEmpty(actual.ToString()).Should().BeTrue({0}).And.ToString();",
newAssertion: "actual.ToString().Should().BeNullOrEmpty({0}).And.ToString();")]
[Implemented]
public void StringShouldBeNullOrEmpty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldBeNullOrEmptyCodeFix, StringShouldBeNullOrEmptyAnalyzer>(oldAssertion, newAssertion);

[AssertionDataTestMethod]
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual).Should().BeTrue({0});")]
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual).Should().BeTrue({0}).And.ToString();")]
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual.ToString()).Should().BeTrue({0});")]
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual.ToString()).Should().BeTrue({0}).And.ToString();")]
[Implemented]
public void StringShouldBeNullOrWhiteSpace_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldBeNullOrWhiteSpaceAnalyzer>(assertion);

[AssertionDataTestMethod]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrWhiteSpace(actual).Should().BeTrue({0});",
newAssertion: "actual.Should().BeNullOrWhiteSpace({0});")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrWhiteSpace(actual).Should().BeTrue({0}).And.ToString();",
newAssertion: "actual.Should().BeNullOrWhiteSpace({0}).And.ToString();")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrWhiteSpace(actual.ToString()).Should().BeTrue({0});",
newAssertion: "actual.ToString().Should().BeNullOrWhiteSpace({0});")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrWhiteSpace(actual.ToString()).Should().BeTrue({0}).And.ToString();",
newAssertion: "actual.ToString().Should().BeNullOrWhiteSpace({0}).And.ToString();")]
[Implemented]
public void StringShouldBeNullOrWhiteSpace_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldBeNullOrWhiteSpaceCodeFix, StringShouldBeNullOrWhiteSpaceAnalyzer>(oldAssertion, newAssertion);

[AssertionDataTestMethod]
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual).Should().BeFalse({0});")]
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual).Should().BeFalse({0}).And.ToString();")]
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual.ToString()).Should().BeFalse({0});")]
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual.ToString()).Should().BeFalse({0}).And.ToString();")]
[Implemented]
public void StringShouldNotBeNullOrWhiteSpace_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldNotBeNullOrWhiteSpaceAnalyzer>(assertion);

[AssertionDataTestMethod]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrWhiteSpace(actual).Should().BeFalse({0});",
newAssertion: "actual.Should().NotBeNullOrWhiteSpace({0});")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrWhiteSpace(actual).Should().BeFalse({0}).And.ToString();",
newAssertion: "actual.Should().NotBeNullOrWhiteSpace({0}).And.ToString();")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrWhiteSpace(actual.ToString()).Should().BeFalse({0});",
newAssertion: "actual.ToString().Should().NotBeNullOrWhiteSpace({0});")]
[AssertionCodeFix(
oldAssertion: "string.IsNullOrWhiteSpace(actual.ToString()).Should().BeFalse({0}).And.ToString();",
newAssertion: "actual.ToString().Should().NotBeNullOrWhiteSpace({0}).And.ToString();")]
[Implemented]
public void StringShouldNotBeNullOrWhiteSpace_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldNotBeNullOrWhiteSpaceCodeFix, StringShouldNotBeNullOrWhiteSpaceAnalyzer>(oldAssertion, newAssertion);

[AssertionDataTestMethod]
[AssertionDiagnostic("actual.Length.Should().Be(k{0});")]
[AssertionDiagnostic("actual.ToString().Length.Should().Be(k{0}).And.ToString();")]
[Implemented]
public void StringShouldHaveLength_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldHaveLengthAnalyzer>(assertion);

[AssertionDataTestMethod]
[AssertionCodeFix(
oldAssertion: "actual.Length.Should().Be(k{0});",
newAssertion: "actual.Should().HaveLength(k{0});")]
[AssertionCodeFix(
oldAssertion: "actual.ToString().Length.Should().Be(k{0}).And.ToString();",
newAssertion: "actual.ToString().Should().HaveLength(k{0}).And.ToString();")]
[Implemented]
public void StringShouldHaveLength_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldHaveLengthCodeFix, StringShouldHaveLengthAnalyzer>(oldAssertion, newAssertion);

private void VerifyCSharpDiagnostic<TDiagnosticAnalyzer>(string sourceAssertion) where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new()
{
var source = GenerateCode.StringAssertion(sourceAssertion);

var type = typeof(TDiagnosticAnalyzer);
var diagnosticId = (string)type.GetField("DiagnosticId").GetValue(null);
var message = (string)type.GetField("Message").GetValue(null);

DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source, new DiagnosticResult
{
Id = diagnosticId,
Message = message,
Locations = new DiagnosticResultLocation[]
{
new DiagnosticResultLocation("Test0.cs", 9, 13)
},
Severity = DiagnosticSeverity.Info
});
}

private void VerifyCSharpFix<TCodeFixProvider, TDiagnosticAnalyzer>(string oldSourceAssertion, string newSourceAssertion)
where TCodeFixProvider : Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider, new()
where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new()
{
var oldSource = GenerateCode.StringAssertion(oldSourceAssertion);
var newSource = GenerateCode.StringAssertion(newSourceAssertion);

DiagnosticVerifier.VerifyCSharpFix<TCodeFixProvider, TDiagnosticAnalyzer>(oldSource, newSource);
}
}
}
13 changes: 11 additions & 2 deletions src/FluentAssertions.Analyzers/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,17 @@ public static class Dictionaries
public const string DictionaryShouldContainPair = nameof(DictionaryShouldContainPair);
public const string DictionaryShouldNotContainKey = nameof(DictionaryShouldNotContainKey);
public const string DictionaryShouldNotContainValue = nameof(DictionaryShouldNotContainValue);

}
}
public static class Strings
{
public const string StringShouldStartWith = nameof(StringShouldStartWith);
public const string StringShouldEndWith = nameof(StringShouldEndWith);
public const string StringShouldNotBeNullOrEmpty = nameof(StringShouldNotBeNullOrEmpty);
public const string StringShouldBeNullOrEmpty = nameof(StringShouldBeNullOrEmpty);
public const string StringShouldBeNullOrWhiteSpace = nameof(StringShouldBeNullOrWhiteSpace);
public const string StringShouldNotBeNullOrWhiteSpace = nameof(StringShouldNotBeNullOrWhiteSpace);
public const string StringShouldHaveLength = nameof(StringShouldHaveLength);
}
}
public static class CodeSmell
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using Microsoft.CodeAnalysis;
using System.Linq;

namespace FluentAssertions.Analyzers
{
public abstract class CollectionAnalyzer : FluentAssertionsAnalyzer
{
protected override bool ShouldAnalyzeVariableType(TypeInfo typeInfo)
{
return typeInfo.ConvertedType.Name != "String"
&& typeInfo.ConvertedType.AllInterfaces.Any(@interface => @interface.Name == "IEnumerable");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace FluentAssertions.Analyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class CollectionShouldBeEmptyAnalyzer : FluentAssertionsAnalyzer
public class CollectionShouldBeEmptyAnalyzer : CollectionAnalyzer
{
public const string DiagnosticId = Constants.Tips.Collections.CollectionsShouldBeEmpty;
public const string Category = Constants.Tips.Category;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace FluentAssertions.Analyzers
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public class CollectionShouldBeInAscendingOrderAnalyzer : FluentAssertionsAnalyzer
public class CollectionShouldBeInAscendingOrderAnalyzer : CollectionAnalyzer
{
public const string DiagnosticId = Constants.Tips.Collections.CollectionShouldBeInAscendingOrder;
public const string Category = Constants.Tips.Category;
Expand Down
Loading

0 comments on commit dcb2c69

Please sign in to comment.