Skip to content

Commit dcb2c69

Browse files
authored
Feature/string assertions (#23)
* added string assertion tests * added string analyzers
1 parent 4f1c7b7 commit dcb2c69

File tree

45 files changed

+758
-52
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+758
-52
lines changed

src/FluentAssertions.Analyzers.Tests/GenerateCode.cs

+24-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static string EnumerableExpressionBodyAssertion(string assertion) => Enum
2121
.AppendLine("{")
2222
.AppendLine(" public class TestClass")
2323
.AppendLine(" {")
24-
.AppendLine($" public void TestMethod(IList<TestComplexClass> actual, IList<TestComplexClass> expected, IList<TestComplexClass> unexpected, TestComplexClass expectedItem, TestComplexClass unexpectedItem, int k)")
24+
.AppendLine(" public void TestMethod(IList<TestComplexClass> actual, IList<TestComplexClass> expected, IList<TestComplexClass> unexpected, TestComplexClass expectedItem, TestComplexClass unexpectedItem, int k)")
2525
.AppendLine(bodyExpression)
2626
.AppendLine(" }")
2727
.AppendLine(" public class TestComplexClass")
@@ -47,7 +47,7 @@ public static string EnumerableExpressionBodyAssertion(string assertion) => Enum
4747
.AppendLine("{")
4848
.AppendLine(" public class TestClass")
4949
.AppendLine(" {")
50-
.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)")
50+
.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)")
5151
.AppendLine(" {")
5252
.AppendLine($" {assertion}")
5353
.AppendLine(" }")
@@ -70,12 +70,33 @@ public static string EnumerableExpressionBodyAssertion(string assertion) => Enum
7070
.AppendLine("{")
7171
.AppendLine(" class TestClass")
7272
.AppendLine(" {")
73-
.AppendLine($" void TestMethod(int actual, int expected)")
73+
.AppendLine(" void TestMethod(int actual, int expected)")
7474
.AppendLine(" {")
7575
.AppendLine($" {assertion}")
7676
.AppendLine(" }")
7777
.AppendLine(" }")
7878
.AppendLine("}")
7979
.ToString();
80+
81+
public static string StringAssertion(string assertion) => new StringBuilder()
82+
.AppendLine("using System;")
83+
.AppendLine("using FluentAssertions;")
84+
.AppendLine("namespace TestNamespace")
85+
.AppendLine("{")
86+
.AppendLine(" class TestClass")
87+
.AppendLine(" {")
88+
.AppendLine(" void TestMethod(string actual, string expected, int k)")
89+
.AppendLine(" {")
90+
.AppendLine($" {assertion}")
91+
.AppendLine(" }")
92+
.AppendLine(" }")
93+
.AppendLine(" class Program")
94+
.AppendLine(" {")
95+
.AppendLine(" public static void Main()")
96+
.AppendLine(" {")
97+
.AppendLine(" }")
98+
.AppendLine(" }")
99+
.AppendLine("}")
100+
.ToString();
80101
}
81102
}

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

+1-8
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,7 @@ namespace FluentAssertions.Analyzers.Tests
77
public class CollectionTests
88
{
99
public TestContext TestContext { get; set; }
10-
11-
[AssertionDataTestMethod]
12-
[AssertionDiagnostic("nestedList.Should().NotBeNull({0}).And.ContainSingle().Which.Should().NotBeEmpty();")]
13-
[AssertionDiagnostic("nestedList.Should().NotBeNull().And.ContainSingle().Which.Should().NotBeEmpty({0});")]
14-
[AssertionDiagnostic("nestedList.Should().NotBeNull().And.ContainSingle({0}).Which.Should().NotBeEmpty();")]
15-
[NotImplemented]
16-
public void NoDiagnostics(string assertion) => VerifyCSharpNoDiagnosticsCodeBlock(assertion);
17-
10+
1811
[AssertionDataTestMethod]
1912
[AssertionDiagnostic("actual.Any().Should().BeTrue({0});")]
2013
[AssertionDiagnostic("actual.AsEnumerable().Any().Should().BeTrue({0}).And.ToString();")]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.VisualStudio.TestTools.UnitTesting;
3+
4+
namespace FluentAssertions.Analyzers.Tests
5+
{
6+
[TestClass]
7+
public class StringTests
8+
{
9+
[AssertionDataTestMethod]
10+
[AssertionDiagnostic("actual.StartsWith(expected).Should().BeTrue({0});")]
11+
[AssertionDiagnostic("actual.ToString().StartsWith(expected).Should().BeTrue({0}).And.ToString();")]
12+
[Implemented]
13+
public void StringShouldStartWith_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldStartWithAnalyzer>(assertion);
14+
15+
[AssertionDataTestMethod]
16+
[AssertionCodeFix(
17+
oldAssertion: "actual.StartsWith(expected).Should().BeTrue({0});",
18+
newAssertion: "actual.Should().StartWith(expected{0});")]
19+
[AssertionCodeFix(
20+
oldAssertion: "actual.ToString().StartsWith(expected).Should().BeTrue({0}).And.ToString();",
21+
newAssertion: "actual.ToString().Should().StartWith(expected{0}).And.ToString();")]
22+
[Implemented]
23+
public void StringShouldStartWith_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldStartWithCodeFix, StringShouldStartWithAnalyzer>(oldAssertion, newAssertion);
24+
25+
[AssertionDataTestMethod]
26+
[AssertionDiagnostic("actual.EndsWith(expected).Should().BeTrue({0});")]
27+
[AssertionDiagnostic("actual.ToString().EndsWith(expected).Should().BeTrue({0}).And.ToString();")]
28+
[Implemented]
29+
public void StringShouldEndWith_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldEndWithAnalyzer>(assertion);
30+
31+
[AssertionDataTestMethod]
32+
[AssertionCodeFix(
33+
oldAssertion: "actual.EndsWith(expected).Should().BeTrue({0});",
34+
newAssertion: "actual.Should().EndWith(expected{0});")]
35+
[AssertionCodeFix(
36+
oldAssertion: "actual.ToString().EndsWith(expected).Should().BeTrue({0}).And.ToString();",
37+
newAssertion: "actual.ToString().Should().EndWith(expected{0}).And.ToString();")]
38+
[Implemented]
39+
public void StringShouldEndWith_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldEndWithCodeFix, StringShouldEndWithAnalyzer>(oldAssertion, newAssertion);
40+
41+
[AssertionDataTestMethod]
42+
[AssertionDiagnostic("actual.Should().NotBeNull().And.NotBeEmpty({0});")]
43+
[AssertionDiagnostic("actual.Should().NotBeNull({0}).And.NotBeEmpty();")]
44+
[AssertionDiagnostic("string.IsNullOrEmpty(actual).Should().BeFalse({0});")]
45+
[AssertionDiagnostic("actual.ToString().Should().NotBeNull().And.NotBeEmpty({0}).And.ToString();")]
46+
[AssertionDiagnostic("actual.ToString().Should().NotBeNull({0}).And.NotBeEmpty().And.ToString();")]
47+
[AssertionDiagnostic("actual.ToString().Should().NotBeEmpty({0}).And.NotBeNull({0}).And.ToString();")]
48+
[AssertionDiagnostic("string.IsNullOrEmpty(actual.ToString()).Should().BeFalse({0}).And.ToString();")]
49+
[Implemented]
50+
public void StringShouldNotBeNullOrEmpty_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldNotBeNullOrEmptyAnalyzer>(assertion);
51+
52+
[AssertionDataTestMethod]
53+
[AssertionCodeFix(
54+
oldAssertion: "actual.Should().NotBeNull({0}).And.NotBeEmpty();",
55+
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
56+
[AssertionCodeFix(
57+
oldAssertion: "actual.Should().NotBeNull().And.NotBeEmpty({0});",
58+
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
59+
[AssertionCodeFix(
60+
oldAssertion: "actual.Should().NotBeEmpty({0}).And.NotBeNull();",
61+
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
62+
[AssertionCodeFix(
63+
oldAssertion: "actual.Should().NotBeEmpty().And.NotBeNull({0});",
64+
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
65+
[AssertionCodeFix(
66+
oldAssertion: "string.IsNullOrEmpty(actual).Should().BeFalse({0});",
67+
newAssertion: "actual.Should().NotBeNullOrEmpty({0});")]
68+
[AssertionCodeFix(
69+
oldAssertion: "actual.ToString().Should().NotBeNull({0}).And.NotBeEmpty().And.ToString();",
70+
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
71+
[AssertionCodeFix(
72+
oldAssertion: "actual.ToString().Should().NotBeNull().And.NotBeEmpty({0}).And.ToString();",
73+
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
74+
[AssertionCodeFix(
75+
oldAssertion: "actual.ToString().Should().NotBeEmpty({0}).And.NotBeNull().And.ToString();",
76+
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
77+
[AssertionCodeFix(
78+
oldAssertion: "actual.ToString().Should().NotBeEmpty().And.NotBeNull({0}).And.ToString();",
79+
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
80+
[AssertionCodeFix(
81+
oldAssertion: "string.IsNullOrEmpty(actual.ToString()).Should().BeFalse({0}).And.ToString();",
82+
newAssertion: "actual.ToString().Should().NotBeNullOrEmpty({0}).And.ToString();")]
83+
[Implemented]
84+
public void StringShouldNotBeNullOrEmpty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldNotBeNullOrEmptyCodeFix, StringShouldNotBeNullOrEmptyAnalyzer>(oldAssertion, newAssertion);
85+
86+
[AssertionDataTestMethod]
87+
[AssertionDiagnostic("string.IsNullOrEmpty(actual).Should().BeTrue({0});")]
88+
[AssertionDiagnostic("string.IsNullOrEmpty(actual).Should().BeTrue({0}).And.ToString();")]
89+
[AssertionDiagnostic("string.IsNullOrEmpty(actual.ToString()).Should().BeTrue({0});")]
90+
[AssertionDiagnostic("string.IsNullOrEmpty(actual.ToString()).Should().BeTrue({0}).And.ToString();")]
91+
[Implemented]
92+
public void StringShouldBeNullOrEmpty_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldBeNullOrEmptyAnalyzer>(assertion);
93+
94+
[AssertionDataTestMethod]
95+
[AssertionCodeFix(
96+
oldAssertion: "string.IsNullOrEmpty(actual).Should().BeTrue({0});",
97+
newAssertion: "actual.Should().BeNullOrEmpty({0});")]
98+
[AssertionCodeFix(
99+
oldAssertion: "string.IsNullOrEmpty(actual).Should().BeTrue({0}).And.ToString();",
100+
newAssertion: "actual.Should().BeNullOrEmpty({0}).And.ToString();")]
101+
[AssertionCodeFix(
102+
oldAssertion: "string.IsNullOrEmpty(actual.ToString()).Should().BeTrue({0});",
103+
newAssertion: "actual.ToString().Should().BeNullOrEmpty({0});")]
104+
[AssertionCodeFix(
105+
oldAssertion: "string.IsNullOrEmpty(actual.ToString()).Should().BeTrue({0}).And.ToString();",
106+
newAssertion: "actual.ToString().Should().BeNullOrEmpty({0}).And.ToString();")]
107+
[Implemented]
108+
public void StringShouldBeNullOrEmpty_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldBeNullOrEmptyCodeFix, StringShouldBeNullOrEmptyAnalyzer>(oldAssertion, newAssertion);
109+
110+
[AssertionDataTestMethod]
111+
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual).Should().BeTrue({0});")]
112+
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual).Should().BeTrue({0}).And.ToString();")]
113+
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual.ToString()).Should().BeTrue({0});")]
114+
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual.ToString()).Should().BeTrue({0}).And.ToString();")]
115+
[Implemented]
116+
public void StringShouldBeNullOrWhiteSpace_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldBeNullOrWhiteSpaceAnalyzer>(assertion);
117+
118+
[AssertionDataTestMethod]
119+
[AssertionCodeFix(
120+
oldAssertion: "string.IsNullOrWhiteSpace(actual).Should().BeTrue({0});",
121+
newAssertion: "actual.Should().BeNullOrWhiteSpace({0});")]
122+
[AssertionCodeFix(
123+
oldAssertion: "string.IsNullOrWhiteSpace(actual).Should().BeTrue({0}).And.ToString();",
124+
newAssertion: "actual.Should().BeNullOrWhiteSpace({0}).And.ToString();")]
125+
[AssertionCodeFix(
126+
oldAssertion: "string.IsNullOrWhiteSpace(actual.ToString()).Should().BeTrue({0});",
127+
newAssertion: "actual.ToString().Should().BeNullOrWhiteSpace({0});")]
128+
[AssertionCodeFix(
129+
oldAssertion: "string.IsNullOrWhiteSpace(actual.ToString()).Should().BeTrue({0}).And.ToString();",
130+
newAssertion: "actual.ToString().Should().BeNullOrWhiteSpace({0}).And.ToString();")]
131+
[Implemented]
132+
public void StringShouldBeNullOrWhiteSpace_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldBeNullOrWhiteSpaceCodeFix, StringShouldBeNullOrWhiteSpaceAnalyzer>(oldAssertion, newAssertion);
133+
134+
[AssertionDataTestMethod]
135+
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual).Should().BeFalse({0});")]
136+
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual).Should().BeFalse({0}).And.ToString();")]
137+
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual.ToString()).Should().BeFalse({0});")]
138+
[AssertionDiagnostic("string.IsNullOrWhiteSpace(actual.ToString()).Should().BeFalse({0}).And.ToString();")]
139+
[Implemented]
140+
public void StringShouldNotBeNullOrWhiteSpace_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldNotBeNullOrWhiteSpaceAnalyzer>(assertion);
141+
142+
[AssertionDataTestMethod]
143+
[AssertionCodeFix(
144+
oldAssertion: "string.IsNullOrWhiteSpace(actual).Should().BeFalse({0});",
145+
newAssertion: "actual.Should().NotBeNullOrWhiteSpace({0});")]
146+
[AssertionCodeFix(
147+
oldAssertion: "string.IsNullOrWhiteSpace(actual).Should().BeFalse({0}).And.ToString();",
148+
newAssertion: "actual.Should().NotBeNullOrWhiteSpace({0}).And.ToString();")]
149+
[AssertionCodeFix(
150+
oldAssertion: "string.IsNullOrWhiteSpace(actual.ToString()).Should().BeFalse({0});",
151+
newAssertion: "actual.ToString().Should().NotBeNullOrWhiteSpace({0});")]
152+
[AssertionCodeFix(
153+
oldAssertion: "string.IsNullOrWhiteSpace(actual.ToString()).Should().BeFalse({0}).And.ToString();",
154+
newAssertion: "actual.ToString().Should().NotBeNullOrWhiteSpace({0}).And.ToString();")]
155+
[Implemented]
156+
public void StringShouldNotBeNullOrWhiteSpace_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldNotBeNullOrWhiteSpaceCodeFix, StringShouldNotBeNullOrWhiteSpaceAnalyzer>(oldAssertion, newAssertion);
157+
158+
[AssertionDataTestMethod]
159+
[AssertionDiagnostic("actual.Length.Should().Be(k{0});")]
160+
[AssertionDiagnostic("actual.ToString().Length.Should().Be(k{0}).And.ToString();")]
161+
[Implemented]
162+
public void StringShouldHaveLength_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<StringShouldHaveLengthAnalyzer>(assertion);
163+
164+
[AssertionDataTestMethod]
165+
[AssertionCodeFix(
166+
oldAssertion: "actual.Length.Should().Be(k{0});",
167+
newAssertion: "actual.Should().HaveLength(k{0});")]
168+
[AssertionCodeFix(
169+
oldAssertion: "actual.ToString().Length.Should().Be(k{0}).And.ToString();",
170+
newAssertion: "actual.ToString().Should().HaveLength(k{0}).And.ToString();")]
171+
[Implemented]
172+
public void StringShouldHaveLength_TestCodeFix(string oldAssertion, string newAssertion) => VerifyCSharpFix<StringShouldHaveLengthCodeFix, StringShouldHaveLengthAnalyzer>(oldAssertion, newAssertion);
173+
174+
private void VerifyCSharpDiagnostic<TDiagnosticAnalyzer>(string sourceAssertion) where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new()
175+
{
176+
var source = GenerateCode.StringAssertion(sourceAssertion);
177+
178+
var type = typeof(TDiagnosticAnalyzer);
179+
var diagnosticId = (string)type.GetField("DiagnosticId").GetValue(null);
180+
var message = (string)type.GetField("Message").GetValue(null);
181+
182+
DiagnosticVerifier.VerifyCSharpDiagnosticUsingAllAnalyzers(source, new DiagnosticResult
183+
{
184+
Id = diagnosticId,
185+
Message = message,
186+
Locations = new DiagnosticResultLocation[]
187+
{
188+
new DiagnosticResultLocation("Test0.cs", 9, 13)
189+
},
190+
Severity = DiagnosticSeverity.Info
191+
});
192+
}
193+
194+
private void VerifyCSharpFix<TCodeFixProvider, TDiagnosticAnalyzer>(string oldSourceAssertion, string newSourceAssertion)
195+
where TCodeFixProvider : Microsoft.CodeAnalysis.CodeFixes.CodeFixProvider, new()
196+
where TDiagnosticAnalyzer : Microsoft.CodeAnalysis.Diagnostics.DiagnosticAnalyzer, new()
197+
{
198+
var oldSource = GenerateCode.StringAssertion(oldSourceAssertion);
199+
var newSource = GenerateCode.StringAssertion(newSourceAssertion);
200+
201+
DiagnosticVerifier.VerifyCSharpFix<TCodeFixProvider, TDiagnosticAnalyzer>(oldSource, newSource);
202+
}
203+
}
204+
}

src/FluentAssertions.Analyzers/Constants.cs

+11-2
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,17 @@ public static class Dictionaries
5757
public const string DictionaryShouldContainPair = nameof(DictionaryShouldContainPair);
5858
public const string DictionaryShouldNotContainKey = nameof(DictionaryShouldNotContainKey);
5959
public const string DictionaryShouldNotContainValue = nameof(DictionaryShouldNotContainValue);
60-
61-
}
60+
}
61+
public static class Strings
62+
{
63+
public const string StringShouldStartWith = nameof(StringShouldStartWith);
64+
public const string StringShouldEndWith = nameof(StringShouldEndWith);
65+
public const string StringShouldNotBeNullOrEmpty = nameof(StringShouldNotBeNullOrEmpty);
66+
public const string StringShouldBeNullOrEmpty = nameof(StringShouldBeNullOrEmpty);
67+
public const string StringShouldBeNullOrWhiteSpace = nameof(StringShouldBeNullOrWhiteSpace);
68+
public const string StringShouldNotBeNullOrWhiteSpace = nameof(StringShouldNotBeNullOrWhiteSpace);
69+
public const string StringShouldHaveLength = nameof(StringShouldHaveLength);
70+
}
6271
}
6372
public static class CodeSmell
6473
{
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Microsoft.CodeAnalysis;
2+
using System.Linq;
3+
4+
namespace FluentAssertions.Analyzers
5+
{
6+
public abstract class CollectionAnalyzer : FluentAssertionsAnalyzer
7+
{
8+
protected override bool ShouldAnalyzeVariableType(TypeInfo typeInfo)
9+
{
10+
return typeInfo.ConvertedType.Name != "String"
11+
&& typeInfo.ConvertedType.AllInterfaces.Any(@interface => @interface.Name == "IEnumerable");
12+
}
13+
}
14+
}

src/FluentAssertions.Analyzers/Tips/Collections/CollectionShouldBeEmpty.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
namespace FluentAssertions.Analyzers
1111
{
1212
[DiagnosticAnalyzer(LanguageNames.CSharp)]
13-
public class CollectionShouldBeEmptyAnalyzer : FluentAssertionsAnalyzer
13+
public class CollectionShouldBeEmptyAnalyzer : CollectionAnalyzer
1414
{
1515
public const string DiagnosticId = Constants.Tips.Collections.CollectionsShouldBeEmpty;
1616
public const string Category = Constants.Tips.Category;

src/FluentAssertions.Analyzers/Tips/Collections/CollectionShouldBeInAscendingOrder.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
namespace FluentAssertions.Analyzers
1010
{
1111
[DiagnosticAnalyzer(LanguageNames.CSharp)]
12-
public class CollectionShouldBeInAscendingOrderAnalyzer : FluentAssertionsAnalyzer
12+
public class CollectionShouldBeInAscendingOrderAnalyzer : CollectionAnalyzer
1313
{
1414
public const string DiagnosticId = Constants.Tips.Collections.CollectionShouldBeInAscendingOrder;
1515
public const string Category = Constants.Tips.Category;

0 commit comments

Comments
 (0)