1111namespace FluentAssertions . Analyzers ;
1212
1313[ ExportCodeFixProvider ( LanguageNames . CSharp , Name = nameof ( NunitCodeFixProvider ) ) , Shared ]
14- public class NunitCodeFixProvider : TestingFrameworkCodeFixProvider
14+ public class NunitCodeFixProvider : TestingFrameworkCodeFixProvider < NunitCodeFixProvider . NunitCodeFixContext >
1515{
1616 public override ImmutableArray < string > FixableDiagnosticIds => ImmutableArray . Create ( AssertAnalyzer . NUnitRule . Id ) ;
17- protected override CreateChangedDocument TryComputeFixCore ( IInvocationOperation invocation , CodeFixContext context , TestingFrameworkCodeFixContext t , Diagnostic diagnostic )
17+ protected override NunitCodeFixContext CreateTestContext ( SemanticModel semanticModel ) => new ( semanticModel . Compilation ) ;
18+ protected override CreateChangedDocument TryComputeFixCore ( IInvocationOperation invocation , CodeFixContext context , NunitCodeFixContext t , Diagnostic diagnostic )
1819 {
1920 var assertType = invocation . TargetMethod . ContainingType ;
2021 var nunitVersion = assertType . ContainingAssembly . Identity . Version ;
@@ -24,6 +25,7 @@ protected override CreateChangedDocument TryComputeFixCore(IInvocationOperation
2425
2526 return assertType . Name switch
2627 {
28+ "Assert" when invocation . TargetMethod . Name is "That" => TryComputeFixForNunitThat ( invocation , context , t ) ,
2729 "Assert" when isNunit3 => TryComputeFixForNunitClassicAssert ( invocation , context , t ) ,
2830 "ClassicAssert" when isNunit4 => TryComputeFixForNunitClassicAssert ( invocation , context , t ) ,
2931 //"StringAssert" => TryComputeFixForStringAssert(invocation, context, testContext),
@@ -32,7 +34,7 @@ protected override CreateChangedDocument TryComputeFixCore(IInvocationOperation
3234 } ;
3335 }
3436
35- private CreateChangedDocument TryComputeFixForNunitClassicAssert ( IInvocationOperation invocation , CodeFixContext context , TestingFrameworkCodeFixContext t )
37+ private CreateChangedDocument TryComputeFixForNunitClassicAssert ( IInvocationOperation invocation , CodeFixContext context , NunitCodeFixContext t )
3638 {
3739 switch ( invocation . TargetMethod . Name )
3840 {
@@ -228,4 +230,41 @@ private CreateChangedDocument TryComputeFixForNunitClassicAssert(IInvocationOper
228230 }
229231 return null ;
230232 }
233+
234+ private CreateChangedDocument TryComputeFixForNunitThat ( IInvocationOperation invocation , CodeFixContext context , NunitCodeFixContext t )
235+ {
236+ if ( invocation . Arguments . Length is 1 && invocation . Arguments [ 0 ] . Value . Type . EqualsSymbol ( t . Boolean ) // Assert.That(subject)
237+ || invocation . Arguments . Length > 2 && invocation . Arguments [ 0 ] . Value . Type . EqualsSymbol ( t . Boolean ) && invocation . Arguments [ 1 ] . Value . Type . EqualsSymbol ( t . String ) ) // Assert.That(subject, message)
238+ {
239+ return DocumentEditorUtils . RenameMethodToSubjectShouldAssertion ( invocation , context , "BeTrue" , subjectIndex : 0 , argumentsToRemove : [ ] ) ;
240+ }
241+
242+ if ( invocation . Arguments [ 1 ] . Value . UnwrapConversion ( ) is not IPropertyReferenceOperation constraint ) return null ;
243+
244+ switch ( constraint . Property . Name )
245+ {
246+ case "True" when constraint . Property . ContainingType . EqualsSymbol ( t . Is ) : // Assert.That(subject, Is.True)
247+ case "False" when constraint . Instance is IPropertyReferenceOperation { Property . Name : "Not" } chainedReference && PropertyReferencedFromType ( chainedReference , t . Is ) : // Assert.That(subject, Is.Not.False)
248+ return DocumentEditorUtils . RenameMethodToSubjectShouldAssertion ( invocation , context , "BeTrue" , subjectIndex : 0 , argumentsToRemove : [ 1 ] ) ;
249+ case "True" when constraint . Instance is IPropertyReferenceOperation { Property . Name : "Not" } chainedReference && PropertyReferencedFromType ( chainedReference , t . Is ) : // Assert.That(subject, Is.Not.True)
250+ case "False" when PropertyReferencedFromType ( constraint , t . Is ) : // Assert.That(subject, Is.False)
251+ return DocumentEditorUtils . RenameMethodToSubjectShouldAssertion ( invocation , context , "BeFalse" , subjectIndex : 0 , argumentsToRemove : [ 1 ] ) ;
252+
253+ default :
254+ return null ;
255+ }
256+
257+ }
258+
259+ private static bool PropertyReferencedFromType ( IPropertyReferenceOperation propertyReference , INamedTypeSymbol type ) => propertyReference . Property . ContainingType . EqualsSymbol ( type ) ;
260+
261+ public class NunitCodeFixContext ( Compilation compilation ) : TestingFrameworkCodeFixProvider . TestingFrameworkCodeFixContext ( compilation )
262+ {
263+ public INamedTypeSymbol Is { get ; } = compilation . GetTypeByMetadataName ( "NUnit.Framework.Is" ) ;
264+ public INamedTypeSymbol Has { get ; } = compilation . GetTypeByMetadataName ( "NUnit.Framework.Has" ) ;
265+ public INamedTypeSymbol Does { get ; } = compilation . GetTypeByMetadataName ( "NUnit.Framework.Does" ) ;
266+ public INamedTypeSymbol Contains { get ; } = compilation . GetTypeByMetadataName ( "NUnit.Framework.Contains" ) ;
267+ public INamedTypeSymbol Throws { get ; } = compilation . GetTypeByMetadataName ( "NUnit.Framework.Throws" ) ;
268+ public INamedTypeSymbol ConstraintExpression { get ; } = compilation . GetTypeByMetadataName ( "NUnit.Framework.Constraints.ConstraintExpression" ) ;
269+ }
231270}
0 commit comments