@@ -350,33 +350,70 @@ public static void IsOrdered(IEnumerable collection, IComparer comparer)
350
350
return null ;
351
351
}
352
352
353
- /* TODO:
354
- StringAssert:
355
-
356
- public static void Contains(string expected, string actual, string message, params object[] args)
357
- public static void Contains(string expected, string actual)
358
- public static void DoesNotContain(string expected, string actual, string message, params object[] args)
359
- public static void DoesNotContain(string expected, string actual)
360
- public static void StartsWith(string expected, string actual, string message, params object[] args)
361
- public static void StartsWith(string expected, string actual)
362
- public static void DoesNotStartWith(string expected, string actual, string message, params object[] args)
363
- public static void DoesNotStartWith(string expected, string actual)
364
- public static void EndsWith(string expected, string actual, string message, params object[] args)
365
- public static void EndsWith(string expected, string actual)
366
- public static void DoesNotEndWith(string expected, string actual, string message, params object[] args)
367
- public static void DoesNotEndWith(string expected, string actual)
368
- public static void AreEqualIgnoringCase(string expected, string actual, string message, params object[] args)
369
- public static void AreEqualIgnoringCase(string expected, string actual)
370
- public static void AreNotEqualIgnoringCase(string expected, string actual, string message, params object[] args)
371
- public static void AreNotEqualIgnoringCase(string expected, string actual)
372
- public static void IsMatch(string pattern, string actual, string message, params object[] args)
373
- public static void IsMatch(string pattern, string actual)
374
- public static void DoesNotMatch(string pattern, string actual, string message, params object[] args)
375
- public static void DoesNotMatch(string pattern, string actual)
376
- */
353
+ /* TODO:
354
+ StringAssert:
355
+
356
+ public static void Contains(string expected, string actual, string message, params object[] args)
357
+ public static void Contains(string expected, string actual)
358
+ public static void DoesNotContain(string expected, string actual, string message, params object[] args)
359
+ public static void DoesNotContain(string expected, string actual)
360
+ public static void StartsWith(string expected, string actual, string message, params object[] args)
361
+ public static void StartsWith(string expected, string actual)
362
+ public static void DoesNotStartWith(string expected, string actual, string message, params object[] args)
363
+ public static void DoesNotStartWith(string expected, string actual)
364
+ public static void EndsWith(string expected, string actual, string message, params object[] args)
365
+ public static void EndsWith(string expected, string actual)
366
+ public static void DoesNotEndWith(string expected, string actual, string message, params object[] args)
367
+ public static void DoesNotEndWith(string expected, string actual)
368
+ public static void AreEqualIgnoringCase(string expected, string actual, string message, params object[] args)
369
+ public static void AreEqualIgnoringCase(string expected, string actual)
370
+ public static void AreNotEqualIgnoringCase(string expected, string actual, string message, params object[] args)
371
+ public static void AreNotEqualIgnoringCase(string expected, string actual)
372
+ public static void IsMatch(string pattern, string actual, string message, params object[] args)
373
+ public static void IsMatch(string pattern, string actual)
374
+ public static void DoesNotMatch(string pattern, string actual, string message, params object[] args)
375
+ public static void DoesNotMatch(string pattern, string actual)
376
+ */
377
377
378
378
private CreateChangedDocument TryComputeFixForNunitThat ( IInvocationOperation invocation , CodeFixContext context , NunitCodeFixContext t )
379
379
{
380
+ /*
381
+ public static ConstraintExpression All;
382
+ public static DefaultConstraint Default;
383
+ public static GreaterThanConstraint Positive;
384
+ public static LessThanConstraint Negative;
385
+ public static NaNConstraint NaN;
386
+ public static EmptyConstraint Empty;
387
+ public static UniqueItemsConstraint Unique;
388
+ public static XmlSerializableConstraint XmlSerializable;
389
+ public static CollectionOrderedConstraint Ordered;
390
+ public static EqualConstraint EqualTo(object? expected);
391
+ public static SameAsConstraint SameAs(object? expected);
392
+ public static GreaterThanConstraint GreaterThan(object expected);
393
+ public static GreaterThanOrEqualConstraint GreaterThanOrEqualTo(object expected);
394
+ public static GreaterThanOrEqualConstraint AtLeast(object expected);
395
+ public static LessThanConstraint LessThan(object expected);
396
+ public static LessThanOrEqualConstraint LessThanOrEqualTo(object expected);
397
+ public static LessThanOrEqualConstraint AtMost(object expected);
398
+ public static ExactTypeConstraint TypeOf(Type expectedType);
399
+ public static ExactTypeConstraint TypeOf<TExpected>();
400
+ public static InstanceOfTypeConstraint InstanceOf(Type expectedType);
401
+ public static InstanceOfTypeConstraint InstanceOf<TExpected>();
402
+ public static AssignableFromConstraint AssignableFrom(Type expectedType);
403
+ public static AssignableFromConstraint AssignableFrom<TExpected>();
404
+ public static AssignableToConstraint AssignableTo(Type expectedType);
405
+ public static AssignableToConstraint AssignableTo<TExpected>();
406
+ public static CollectionEquivalentConstraint EquivalentTo(IEnumerable expected);
407
+ public static CollectionSubsetConstraint SubsetOf(IEnumerable expected);
408
+ public static CollectionSupersetConstraint SupersetOf(IEnumerable expected);
409
+ public static SamePathConstraint SamePath(string expected);
410
+ public static SubPathConstraint SubPathOf(string expected);
411
+ public static SamePathOrUnderConstraint SamePathOrUnder(string expected);
412
+ public static RangeConstraint InRange(object from, object to);
413
+ public static AnyOfConstraint AnyOf(params object?[]? expected);
414
+ public static AnyOfConstraint AnyOf(ICollection expected);
415
+ */
416
+
380
417
// Assert.That(condition)
381
418
if ( invocation . Arguments [ 0 ] . Value . Type . EqualsSymbol ( t . Boolean )
382
419
&& ( invocation . Arguments . Length is 1
@@ -393,29 +430,29 @@ private CreateChangedDocument TryComputeFixForNunitThat(IInvocationOperation inv
393
430
if ( invocation . Arguments [ 1 ] . Value . UnwrapConversion ( ) is not IPropertyReferenceOperation constraint ) return null ;
394
431
var subject = invocation . Arguments [ 0 ] . Value ;
395
432
396
- if ( IsPropertyOfSymbol ( constraint , "True" , t . Is ) // Assert.That(subject, Is.True)
397
- || IsPropertyOfSymbol ( constraint , "Not" , "False" , t . Is ) ) // Assert.That(subject, Is.False)
433
+ if ( MatchesProperties ( constraint , t . Is , "True" ) // Assert.That(subject, Is.True)
434
+ || MatchesProperties ( constraint , t . Is , "Not" , "False" ) ) // Assert.That(subject, Is.Not .False)
398
435
return RenameAssertThatAssertionToSubjectShouldAssertion ( "BeTrue" ) ;
399
- else if ( IsPropertyOfSymbol ( constraint , "False" , t . Is ) // Assert.That(subject, Is.False)
400
- || IsPropertyOfSymbol ( constraint , "Not" , "True" , t . Is ) ) // Assert.That(subject, Is.Not.True)
436
+ else if ( MatchesProperties ( constraint , t . Is , "False" ) // Assert.That(subject, Is.False)
437
+ || MatchesProperties ( constraint , t . Is , "Not" , "True" ) ) // Assert.That(subject, Is.Not.True)
401
438
return RenameAssertThatAssertionToSubjectShouldAssertion ( "BeFalse" ) ;
402
- else if ( IsPropertyOfSymbol ( constraint , "Null" , t . Is ) ) // Assert.That(subject, Is.Null)
439
+ else if ( MatchesProperties ( constraint , t . Is , "Null" ) ) // Assert.That(subject, Is.Null)
403
440
return RenameAssertThatAssertionToSubjectShouldAssertion ( "BeNull" ) ;
404
- else if ( IsPropertyOfSymbol ( constraint , "Not" , "Null" , t . Is ) ) // Assert.That(subject, Is.Not.Null)
441
+ else if ( MatchesProperties ( constraint , t . Is , "Not" , "Null" ) ) // Assert.That(subject, Is.Not.Null)
405
442
return RenameAssertThatAssertionToSubjectShouldAssertion ( "NotBeNull" ) ;
406
443
else if ( ! IsArgumentTypeOfNonGenericEnumerable ( invocation , argumentIndex : 0 ) )
407
444
{
408
- if ( IsPropertyOfSymbol ( constraint , "Empty" , t . Is ) ) // Assert.That(subject, Is.Empty)
445
+ if ( MatchesProperties ( constraint , t . Is , "Empty" ) ) // Assert.That(subject, Is.Empty)
409
446
return RenameAssertThatAssertionToSubjectShouldAssertion ( "BeEmpty" ) ;
410
- else if ( IsPropertyOfSymbol ( constraint , "Not" , "Empty" , t . Is ) ) // Assert.That(subject, Is.Not.Empty)
447
+ else if ( MatchesProperties ( constraint , t . Is , "Not" , "Empty" ) ) // Assert.That(subject, Is.Not.Empty)
411
448
return RenameAssertThatAssertionToSubjectShouldAssertion ( "NotBeEmpty" ) ;
412
449
}
413
- if ( IsPropertyOfSymbol ( constraint , "Zero" , t . Is ) )
450
+ if ( MatchesProperties ( constraint , t . Is , "Zero" ) )
414
451
return DocumentEditorUtils . RewriteExpression ( invocation , [
415
452
EditAction . ReplaceAssertionArgument ( index : 1 , generator => generator . LiteralExpression ( 0 ) ) ,
416
453
EditAction . SubjectShouldAssertion ( argumentIndex : 0 , "Be" ) ,
417
454
] , context ) ;
418
- else if ( IsPropertyOfSymbol ( constraint , "Not" , "Zero" , t . Is ) )
455
+ else if ( MatchesProperties ( constraint , t . Is , "Not" , "Zero" ) )
419
456
return DocumentEditorUtils . RewriteExpression ( invocation , [
420
457
EditAction . ReplaceAssertionArgument ( index : 1 , generator => generator . LiteralExpression ( 0 ) ) ,
421
458
EditAction . SubjectShouldAssertion ( argumentIndex : 0 , "NotBe" ) ,
@@ -453,12 +490,44 @@ private CreateChangedDocument RewriteContainsAssertion(IInvocationOperation invo
453
490
] , context ) ;
454
491
}
455
492
456
- private static bool IsPropertyReferencedFromType ( IPropertyReferenceOperation propertyReference , INamedTypeSymbol type )
457
- => propertyReference . Property . ContainingType . EqualsSymbol ( type ) ;
458
- private static bool IsPropertyOfSymbol ( IPropertyReferenceOperation propertyReference , string firstProperty , string secondProperty , INamedTypeSymbol type )
459
- => propertyReference . Property . Name == secondProperty && IsPropertyOfSymbol ( propertyReference . Instance , firstProperty , type ) ;
460
- private static bool IsPropertyOfSymbol ( IOperation operation , string property , INamedTypeSymbol type )
461
- => operation is IPropertyReferenceOperation propertyReference && propertyReference . Property . Name == property && IsPropertyReferencedFromType ( propertyReference , type ) ;
493
+ private interface IOperationMatcher
494
+ {
495
+ ( IOperation op , ISymbol containingType ) TryGetNext ( IOperation operation ) ;
496
+ }
497
+ private class MethodInvocationMatcher ( string name ) : IOperationMatcher
498
+ {
499
+ public ( IOperation op , ISymbol containingType ) TryGetNext ( IOperation operation )
500
+ => operation is IInvocationOperation invocation && invocation . TargetMethod . Name == name ? ( invocation . Instance , invocation . TargetMethod . ContainingType ) : ( null , null ) ;
501
+ }
502
+ private class PropertyReferenceMatcher ( string name ) : IOperationMatcher
503
+ {
504
+ public ( IOperation op , ISymbol containingType ) TryGetNext ( IOperation operation )
505
+ => operation is IPropertyReferenceOperation propertyReference && propertyReference . Property . Name == name ? ( propertyReference . Instance , propertyReference . Member . ContainingType ) : ( null , null ) ;
506
+ }
507
+ private static IOperationMatcher Method ( string name ) => new MethodInvocationMatcher ( name ) ;
508
+ private static IOperationMatcher Property ( string name ) => new PropertyReferenceMatcher ( name ) ;
509
+ private static bool MatchesProperties ( IOperation constraint , INamedTypeSymbol type , params string [ ] matchers )
510
+ => Matches ( constraint , type , Array . ConvertAll ( matchers , matcher => new PropertyReferenceMatcher ( matcher ) ) ) ;
511
+ private static bool Matches ( IOperation constraint , INamedTypeSymbol type , params IOperationMatcher [ ] matchers )
512
+ {
513
+ var currentOp = constraint ;
514
+ for ( var i = matchers . Length - 1 ; i >= 0 ; i -- )
515
+ {
516
+ var ( nextOp , containingType ) = matchers [ i ] . TryGetNext ( currentOp ) ;
517
+ if ( containingType is null ) return false ;
518
+
519
+ if ( i is 0 )
520
+ {
521
+ return containingType . EqualsSymbol ( type ) ;
522
+ }
523
+
524
+ if ( nextOp is null ) return false ;
525
+
526
+ currentOp = nextOp ;
527
+ }
528
+
529
+ return false ;
530
+ }
462
531
463
532
private static bool IsArgumentTypeOfNonGenericEnumerable ( IInvocationOperation invocation , int argumentIndex ) => IsArgumentTypeOf ( invocation , argumentIndex , SpecialType . System_Collections_IEnumerable ) ;
464
533
private static bool IsArgumentTypeOf ( IInvocationOperation invocation , int argumentIndex , SpecialType type )
0 commit comments