Skip to content

Commit 3eb6906

Browse files
Issue 171 - when expect value is null object (#176)
* issue-171 --------- Co-authored-by: Meir Blachman <[email protected]>
1 parent 7445e62 commit 3eb6906

File tree

5 files changed

+98
-12
lines changed

5 files changed

+98
-12
lines changed

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,32 @@ public void AssertIsNotInstanceOfType_TestCodeFix(string oldAssertion, string ne
310310
public void AssertObjectAreEqual_TestCodeFix(string oldAssertion, string newAssertion)
311311
=> VerifyCSharpFix<AssertAreEqualCodeFix, AssertAreEqualAnalyzer>("object actual, object expected", oldAssertion, newAssertion);
312312

313+
[AssertionDataTestMethod]
314+
[AssertionDiagnostic("Assert.AreEqual(expected, actual{0});")]
315+
[Implemented]
316+
public void AssertOptionalIntAreEqual_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<AssertAreEqualAnalyzer>("int? actual, int? expected", assertion);
317+
318+
[AssertionDataTestMethod]
319+
[AssertionCodeFix(
320+
oldAssertion: "Assert.AreEqual(expected, actual{0});",
321+
newAssertion: "actual.Should().Be(expected{0});")]
322+
[Implemented]
323+
public void AssertOptionalIntAreEqual_TestCodeFix(string oldAssertion, string newAssertion)
324+
=> VerifyCSharpFix<AssertAreEqualCodeFix, AssertAreEqualAnalyzer>("int? actual, int? expected", oldAssertion, newAssertion);
325+
326+
[AssertionDataTestMethod]
327+
[AssertionDiagnostic("Assert.AreEqual(actual, null{0});")]
328+
[Implemented]
329+
public void AssertOptionalIntAndNullAreEqual_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<AssertAreEqualAnalyzer>("int? actual", assertion);
330+
331+
[AssertionDataTestMethod]
332+
[AssertionCodeFix(
333+
oldAssertion: "Assert.AreEqual(actual, null{0});",
334+
newAssertion: "actual.Should().BeNull({0});")]
335+
[Implemented]
336+
public void AssertOptionalIntAndNullAreEqual_TestCodeFix(string oldAssertion, string newAssertion)
337+
=> VerifyCSharpFix<AssertAreEqualCodeFix, AssertAreEqualAnalyzer>("int? actual", oldAssertion, newAssertion);
338+
313339
[AssertionDataTestMethod]
314340
[AssertionDiagnostic("Assert.AreEqual(expected, actual, delta{0});")]
315341
[AssertionDiagnostic("Assert.AreEqual(expected, actual, 0.6{0});")]
@@ -403,6 +429,33 @@ public void AssertObjectAreNotEqual_TestCodeFix(string oldAssertion, string newA
403429
public void AssertDoubleAreNotEqual_TestCodeFix(string oldAssertion, string newAssertion)
404430
=> VerifyCSharpFix<AssertAreNotEqualCodeFix, AssertAreNotEqualAnalyzer>("double actual, double expected, double delta", oldAssertion, newAssertion);
405431

432+
433+
[AssertionDataTestMethod]
434+
[AssertionDiagnostic("Assert.AreNotEqual(expected, actual{0});")]
435+
[Implemented]
436+
public void AssertOptionalIntAreNotEqual_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<AssertAreNotEqualAnalyzer>("int? actual, int? expected", assertion);
437+
438+
[AssertionDataTestMethod]
439+
[AssertionCodeFix(
440+
oldAssertion: "Assert.AreNotEqual(expected, actual{0});",
441+
newAssertion: "actual.Should().NotBe(expected{0});")]
442+
[Implemented]
443+
public void AssertOptionalIntAreNotEqual_TestCodeFix(string oldAssertion, string newAssertion)
444+
=> VerifyCSharpFix<AssertAreNotEqualCodeFix, AssertAreNotEqualAnalyzer>("int? actual, int? expected", oldAssertion, newAssertion);
445+
446+
[AssertionDataTestMethod]
447+
[AssertionDiagnostic("Assert.AreNotEqual(actual, null{0});")]
448+
[Implemented]
449+
public void AssertOptionalIntAndNullAreNotEqual_TestAnalyzer(string assertion) => VerifyCSharpDiagnostic<AssertAreNotEqualAnalyzer>("int? actual", assertion);
450+
451+
[AssertionDataTestMethod]
452+
[AssertionCodeFix(
453+
oldAssertion: "Assert.AreNotEqual(actual, null{0});",
454+
newAssertion: "actual.Should().NotBeNull({0});")]
455+
[Implemented]
456+
public void AssertOptionalIntAndNullAreNotEqual_TestCodeFix(string oldAssertion, string newAssertion)
457+
=> VerifyCSharpFix<AssertAreNotEqualCodeFix, AssertAreNotEqualAnalyzer>("int? actual", oldAssertion, newAssertion);
458+
406459
[AssertionDataTestMethod]
407460
[AssertionDiagnostic("Assert.AreNotEqual(expected, actual, delta{0});")]
408461
[AssertionDiagnostic("Assert.AreNotEqual(expected, actual, 0.6f{0});")]

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
2727
yield return new AssertFloatAreEqualWithDeltaSyntaxVisitor();
2828
yield return new AssertDoubleAreEqualWithDeltaSyntaxVisitor();
2929
yield return new AssertStringAreEqualSyntaxVisitor();
30+
yield return new AssertObjectAreEqualNullSyntaxVisitor();
3031
yield return new AssertObjectAreEqualSyntaxVisitor();
3132
}
3233
}
@@ -69,6 +70,16 @@ public AssertStringAreEqualSyntaxVisitor() : base(
6970
}
7071
}
7172

73+
public class AssertObjectAreEqualNullSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
74+
{
75+
public AssertObjectAreEqualNullSyntaxVisitor() : base(
76+
MemberValidator.ArgumentsMatch("AreEqual",
77+
ArgumentValidator.IsIdentifier(),
78+
ArgumentValidator.IsNull()))
79+
{
80+
}
81+
}
82+
7283
// public static void AreEqual<T>(T expected, T actual)
7384
// public static void AreEqual(object expected, object actual)
7485
public class AssertObjectAreEqualSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
@@ -96,6 +107,9 @@ protected override async Task<ExpressionSyntax> GetNewExpressionAsync(Expression
96107
case nameof(AssertAreEqualAnalyzer.AssertStringAreEqualSyntaxVisitor):
97108
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
98109
return GetNewExpressionForAreNotEqualOrAreEqualStrings(expression, semanticModel, "AreEqual", "Be", "BeEquivalentTo");
110+
case nameof(AssertAreEqualAnalyzer.AssertObjectAreEqualNullSyntaxVisitor):
111+
expression = RenameMethodAndReplaceWithSubjectShould(expression, "AreEqual", "BeNull");
112+
return GetNewExpression(expression, NodeReplacement.RemoveFirstArgument("BeNull"));
99113
default:
100114
throw new System.InvalidOperationException($"Invalid visitor name - {properties.VisitorName}");
101115
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ protected override IEnumerable<FluentAssertionsCSharpSyntaxVisitor> Visitors
2727
yield return new AssertFloatAreNotEqualWithDeltaSyntaxVisitor();
2828
yield return new AssertDoubleAreNotEqualWithDeltaSyntaxVisitor();
2929
yield return new AssertStringAreNotEqualSyntaxVisitor();
30+
yield return new AssertObjectAreNotEqualNullSyntaxVisitor();
3031
yield return new AssertObjectAreNotEqualSyntaxVisitor();
3132
}
3233
}
@@ -57,6 +58,16 @@ public AssertDoubleAreNotEqualWithDeltaSyntaxVisitor() : base(
5758
}
5859
}
5960

61+
public class AssertObjectAreNotEqualNullSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
62+
{
63+
public AssertObjectAreNotEqualNullSyntaxVisitor() : base(
64+
MemberValidator.ArgumentsMatch("AreNotEqual",
65+
ArgumentValidator.IsIdentifier(),
66+
ArgumentValidator.IsNull()))
67+
{
68+
}
69+
}
70+
6071
// public static void AreNotEqual(string expected, string actual, bool ignoreCase, CultureInfo culture
6172
public class AssertStringAreNotEqualSyntaxVisitor : FluentAssertionsCSharpSyntaxVisitor
6273
{
@@ -97,6 +108,9 @@ protected override async Task<ExpressionSyntax> GetNewExpressionAsync(Expression
97108
case nameof(AssertAreNotEqualAnalyzer.AssertStringAreNotEqualSyntaxVisitor):
98109
var semanticModel = await document.GetSemanticModelAsync(cancellationToken);
99110
return GetNewExpressionForAreNotEqualOrAreEqualStrings(expression, semanticModel, "AreNotEqual", "NotBe", "NotBeEquivalentTo");
111+
case nameof(AssertAreNotEqualAnalyzer.AssertObjectAreNotEqualNullSyntaxVisitor):
112+
expression = RenameMethodAndReplaceWithSubjectShould(expression, "AreNotEqual", "NotBeNull");
113+
return GetNewExpression(expression, NodeReplacement.RemoveFirstArgument("NotBeNull"));
100114
default:
101115
throw new System.InvalidOperationException($"Invalid visitor name - {properties.VisitorName}");
102116
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using System;
5+
6+
namespace FluentAssertions.Analyzers
7+
{
8+
public class ArgumentValidator
9+
{
10+
public static ArgumentPredicate IsIdentifier()
11+
=> (argument, semanticModel) => argument.Expression.IsKind(SyntaxKind.IdentifierName);
12+
public static ArgumentPredicate IsType(Func<SemanticModel, INamedTypeSymbol> typeSelector)
13+
=> (argument, semanticModel) => semanticModel.GetTypeInfo(argument.Expression).Type.Equals(typeSelector(semanticModel), SymbolEqualityComparer.Default);
14+
public static ArgumentPredicate IsNull()
15+
=> (argument, semanticModel) => argument.Expression is LiteralExpressionSyntax literal && literal.Token.IsKind(SyntaxKind.NullKeyword);
16+
}
17+
}

src/FluentAssertions.Analyzers/Utilities/MemberValidator.cs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using Microsoft.CodeAnalysis;
22
using Microsoft.CodeAnalysis.CSharp.Syntax;
3-
using System;
43
using System.Diagnostics;
54

65
namespace FluentAssertions.Analyzers
@@ -105,15 +104,4 @@ public static bool ArgumentsMatchPredicate(SeparatedSyntaxList<ArgumentSyntax> a
105104
return true;
106105
}
107106
}
108-
109-
public class ArgumentValidator
110-
{
111-
public static ArgumentPredicate IsType(Func<SemanticModel, INamedTypeSymbol> typeSelector)
112-
{
113-
return (argument, semanticModel) =>
114-
{
115-
return semanticModel.GetTypeInfo(argument.Expression).Type.Equals(typeSelector(semanticModel), SymbolEqualityComparer.Default);
116-
};
117-
}
118-
}
119107
}

0 commit comments

Comments
 (0)