diff --git a/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonVirtualSetupWhenAnalyzer.cs b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonVirtualSetupWhenAnalyzer.cs new file mode 100644 index 00000000..f5f7e8d0 --- /dev/null +++ b/src/NSubstitute.Analyzers.CSharp/DiagnosticAnalyzers/NonVirtualSetupWhenAnalyzer.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; + +namespace NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers +{ + [DiagnosticAnalyzer(LanguageNames.CSharp)] + internal class NonVirtualSetupWhenAnalyzer : AbstractNonVirtualWhenAnalyzer + { + public NonVirtualSetupWhenAnalyzer() + : base(new DiagnosticDescriptorsProvider()) + { + } + + protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; + + protected override IEnumerable GetExpressionsForAnalysys(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocationExpressionSyntax) + { + var argumentListArguments = invocationExpressionSyntax.ArgumentList.Arguments; + var argumentSyntax = methodSymbol.MethodKind == MethodKind.ReducedExtension ? argumentListArguments.First() : argumentListArguments.Skip(1).First(); + return GetExpressionsForAnalysys(syntaxNodeAnalysisContext, argumentSyntax.Expression); + } + + private IEnumerable GetExpressionsForAnalysys(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode argumentSyntax) + { + SyntaxNode body = null; + switch (argumentSyntax) + { + case SimpleLambdaExpressionSyntax simpleLambdaExpressionSyntax: + body = simpleLambdaExpressionSyntax.Body; + break; + case AnonymousFunctionExpressionSyntax anonymousFunctionExpressionSyntax: + body = anonymousFunctionExpressionSyntax.Body; + break; + case LocalFunctionStatementSyntax localFunctionStatementSyntax: + body = (SyntaxNode)localFunctionStatementSyntax.Body ?? localFunctionStatementSyntax.ExpressionBody; + break; + case MethodDeclarationSyntax methodDeclarationSyntax: + body = (SyntaxNode)methodDeclarationSyntax.Body ?? methodDeclarationSyntax.ExpressionBody; + break; + case IdentifierNameSyntax identifierNameSyntax: + var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(identifierNameSyntax); + if (symbol.Symbol != null && symbol.Symbol.Locations.Any()) + { + var location = symbol.Symbol.Locations.First(); + var syntaxNode = location.SourceTree.GetRoot().FindNode(location.SourceSpan); + + foreach (var expressionsForAnalysy in GetExpressionsForAnalysys(syntaxNodeContext, syntaxNode)) + { + yield return expressionsForAnalysy; + } + } + + break; + } + + if (body == null) + { + yield break; + } + + foreach (var invocationExpressionSyntax in body.DescendantNodes().Where(node => node.IsKind(SyntaxKind.SimpleMemberAccessExpression) || + node.IsKind(SyntaxKind.ElementAccessExpression))) + { + yield return invocationExpressionSyntax; + } + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/NSubstitute.Analyzers.CSharp.csproj b/src/NSubstitute.Analyzers.CSharp/NSubstitute.Analyzers.CSharp.csproj index e769f89a..53f88d12 100644 --- a/src/NSubstitute.Analyzers.CSharp/NSubstitute.Analyzers.CSharp.csproj +++ b/src/NSubstitute.Analyzers.CSharp/NSubstitute.Analyzers.CSharp.csproj @@ -1,6 +1,6 @@  - netstandard1.1 + netstandard1.3 portable45-net45+win8 false False @@ -22,7 +22,7 @@ - + diff --git a/src/NSubstitute.Analyzers.CSharp/Resources.Designer.cs b/src/NSubstitute.Analyzers.CSharp/Resources.Designer.cs index 5bf834f0..ff8ceea0 100644 --- a/src/NSubstitute.Analyzers.CSharp/Resources.Designer.cs +++ b/src/NSubstitute.Analyzers.CSharp/Resources.Designer.cs @@ -115,6 +115,33 @@ internal static string NonVirtualSetupSpecificationTitle { } } + /// + /// Looks up a localized string similar to Non-virtual members can not be intercepted.. + /// + internal static string NonVirtualWhenSetupSpecificationDescription { + get { + return ResourceManager.GetString("NonVirtualWhenSetupSpecificationDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Member {0} can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.. + /// + internal static string NonVirtualWhenSetupSpecificationMessageFormat { + get { + return ResourceManager.GetString("NonVirtualWhenSetupSpecificationMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-virtual setup specification.. + /// + internal static string NonVirtualWhenSetupSpecificationTitle { + get { + return ResourceManager.GetString("NonVirtualWhenSetupSpecificationTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to Can not provide constructor arguments when substituting for a delegate.. /// diff --git a/src/NSubstitute.Analyzers.CSharp/Resources.resx b/src/NSubstitute.Analyzers.CSharp/Resources.resx index f9c6e2c7..1c0f14e6 100644 --- a/src/NSubstitute.Analyzers.CSharp/Resources.resx +++ b/src/NSubstitute.Analyzers.CSharp/Resources.resx @@ -261,4 +261,16 @@ Non-virtual setup specification. The title of the diagnostic. + + Non-virtual members can not be intercepted. + An optional longer localizable description of the diagnostic. + + + Member {0} can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted. + The format-able message the diagnostic displays. + + + Non-virtual setup specification. + The title of the diagnostic. + diff --git a/src/NSubstitute.Analyzers.Shared/AbstractDiagnosticDescriptorsProvider.cs b/src/NSubstitute.Analyzers.Shared/AbstractDiagnosticDescriptorsProvider.cs index 76858040..cd0f3752 100644 --- a/src/NSubstitute.Analyzers.Shared/AbstractDiagnosticDescriptorsProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/AbstractDiagnosticDescriptorsProvider.cs @@ -27,5 +27,7 @@ internal class AbstractDiagnosticDescriptorsProvider : IDiagnosticDescriptors public DiagnosticDescriptor SubstituteConstructorArgumentsForDelegate { get; } = DiagnosticDescriptors.SubstituteConstructorArgumentsForDelegate; public DiagnosticDescriptor NonVirtualReceivedSetupSpecification { get; } = DiagnosticDescriptors.NonVirtualReceivedSetupSpecification; + + public DiagnosticDescriptor NonVirtualWhenSetupSpecification { get; } = DiagnosticDescriptors.NonVirtualWhenSetupSpecification; } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonVirtualWhenAnalyzer.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonVirtualWhenAnalyzer.cs new file mode 100644 index 00000000..f41b1929 --- /dev/null +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticAnalyzers/AbstractNonVirtualWhenAnalyzer.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.Shared.Extensions; + +namespace NSubstitute.Analyzers.Shared.DiagnosticAnalyzers +{ + internal abstract class AbstractNonVirtualWhenAnalyzer : AbstractDiagnosticAnalyzer + where TInvocationExpressionSyntax : SyntaxNode + where TSyntaxKind : struct + { + public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(DiagnosticDescriptorsProvider.NonVirtualWhenSetupSpecification); + + private static readonly ImmutableHashSet MethodNames = ImmutableHashSet.Create( + MetadataNames.NSubstituteWhenMethod, + MetadataNames.NSubstituteWhenForAnyArgsMethod); + + protected abstract TSyntaxKind InvocationExpressionKind { get; } + + protected AbstractNonVirtualWhenAnalyzer(IDiagnosticDescriptorsProvider diagnosticDescriptorsProvider) + : base(diagnosticDescriptorsProvider) + { + } + + public override void Initialize(AnalysisContext context) + { + context.RegisterSyntaxNodeAction(AnalyzeInvocation, InvocationExpressionKind); + } + + protected abstract IEnumerable GetExpressionsForAnalysys(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, IMethodSymbol methodSymbol, TInvocationExpressionSyntax invocationExpressionSyntax); + + private void AnalyzeInvocation(SyntaxNodeAnalysisContext syntaxNodeContext) + { + var invocationExpression = (TInvocationExpressionSyntax)syntaxNodeContext.Node; + var methodSymbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(invocationExpression); + + if (methodSymbolInfo.Symbol?.Kind != SymbolKind.Method) + { + return; + } + + var methodSymbol = (IMethodSymbol)methodSymbolInfo.Symbol; + if (methodSymbol == null) + { + return; + } + + if (IsWhenLikeMethod(syntaxNodeContext, invocationExpression, methodSymbol.Name) == false) + { + return; + } + + var expressionsForAnalysys = GetExpressionsForAnalysys(syntaxNodeContext, methodSymbol, invocationExpression); + var typeSymbol = methodSymbol.TypeArguments.FirstOrDefault() ?? methodSymbol.ReceiverType; + foreach (var analysedSyntax in expressionsForAnalysys) + { + var symbolInfo = syntaxNodeContext.SemanticModel.GetSymbolInfo(analysedSyntax); + if (symbolInfo.Symbol != null && symbolInfo.Symbol.ContainingType == typeSymbol && symbolInfo.Symbol.CanBeSetuped() == false) + { + var diagnostic = Diagnostic.Create( + DiagnosticDescriptorsProvider.NonVirtualWhenSetupSpecification, + analysedSyntax.GetLocation(), + symbolInfo.Symbol.Name); + + syntaxNodeContext.ReportDiagnostic(diagnostic); + } + } + } + + private bool IsWhenLikeMethod(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntax, string memberName) + { + if (MethodNames.Contains(memberName) == false) + { + return false; + } + + var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(syntax); + + return symbol.Symbol?.ContainingAssembly?.Name.Equals(MetadataNames.NSubstituteAssemblyName, StringComparison.OrdinalIgnoreCase) == true && + symbol.Symbol?.ContainingType?.ToString().Equals(MetadataNames.NSubstituteSubstituteExtensionsFullTypeName, StringComparison.OrdinalIgnoreCase) == true; + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs index 689be9c6..a06fa5cb 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticDescriptors.cs @@ -107,6 +107,14 @@ internal class DiagnosticDescriptors defaultSeverity: DiagnosticSeverity.Warning, isEnabledByDefault: true); + public static DiagnosticDescriptor NonVirtualWhenSetupSpecification { get; } = + CreateDiagnosticDescriptor( + name: nameof(NonVirtualWhenSetupSpecification), + id: DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + category: DiagnosticCategories.Usage, + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true); + private static DiagnosticDescriptor CreateDiagnosticDescriptor( string name, string id, string category, DiagnosticSeverity defaultSeverity, bool isEnabledByDefault) { diff --git a/src/NSubstitute.Analyzers.Shared/DiagnosticIdentifiers.cs b/src/NSubstitute.Analyzers.Shared/DiagnosticIdentifiers.cs index 212ea303..fb63ed8d 100644 --- a/src/NSubstitute.Analyzers.Shared/DiagnosticIdentifiers.cs +++ b/src/NSubstitute.Analyzers.Shared/DiagnosticIdentifiers.cs @@ -13,5 +13,6 @@ internal class DiagnosticIdentifiers public static readonly string SubstituteConstructorArgumentsForInterface = "NS009"; public static readonly string SubstituteConstructorArgumentsForDelegate = "NS010"; public static readonly string NonVirtualReceivedSetupSpecification = "NS011"; + public static readonly string NonVirtualWhenSetupSpecification = "NS012"; } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/IDiagnosticDescriptorsProvider.cs b/src/NSubstitute.Analyzers.Shared/IDiagnosticDescriptorsProvider.cs index fb6d3626..5696f9fc 100644 --- a/src/NSubstitute.Analyzers.Shared/IDiagnosticDescriptorsProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/IDiagnosticDescriptorsProvider.cs @@ -27,5 +27,7 @@ internal interface IDiagnosticDescriptorsProvider DiagnosticDescriptor SubstituteConstructorArgumentsForDelegate { get; } DiagnosticDescriptor NonVirtualReceivedSetupSpecification { get; } + + DiagnosticDescriptor NonVirtualWhenSetupSpecification { get; } } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/MetadataNames.cs b/src/NSubstitute.Analyzers.Shared/MetadataNames.cs index 990eec95..391516e2 100644 --- a/src/NSubstitute.Analyzers.Shared/MetadataNames.cs +++ b/src/NSubstitute.Analyzers.Shared/MetadataNames.cs @@ -15,5 +15,7 @@ internal class MetadataNames public const string NSubstituteForPartsOfMethod = "ForPartsOf"; public const string InternalsVisibleToAttributeFullTypeName = "System.Runtime.CompilerServices.InternalsVisibleToAttribute"; public const string CastleDynamicProxyGenAssembly2Name = "DynamicProxyGenAssembly2"; + public const string NSubstituteWhenMethod = "When"; + public const string NSubstituteWhenForAnyArgsMethod = "WhenForAnyArgs"; } } \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonVirtualSetupWhenAnalyzer.cs b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonVirtualSetupWhenAnalyzer.cs new file mode 100644 index 00000000..d4da02f8 --- /dev/null +++ b/src/NSubstitute.Analyzers.VisualBasic/DiagnosticAnalyzers/NonVirtualSetupWhenAnalyzer.cs @@ -0,0 +1,114 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; + +namespace NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers +{ + [DiagnosticAnalyzer(LanguageNames.VisualBasic)] + internal class NonVirtualSetupWhenAnalyzer : AbstractNonVirtualWhenAnalyzer + { + public NonVirtualSetupWhenAnalyzer() + : base(new DiagnosticDescriptorsProvider()) + { + } + + protected override SyntaxKind InvocationExpressionKind { get; } = SyntaxKind.InvocationExpression; + + protected override IEnumerable GetExpressionsForAnalysys(SyntaxNodeAnalysisContext syntaxNodeAnalysisContext, IMethodSymbol methodSymbol, InvocationExpressionSyntax invocationExpressionSyntax) + { + var argumentListArguments = invocationExpressionSyntax.ArgumentList.Arguments; + var argumentSyntax = methodSymbol.MethodKind == MethodKind.ReducedExtension ? argumentListArguments.First() : argumentListArguments.Skip(1).First(); + return GetExpressionsForAnalysys(syntaxNodeAnalysisContext, argumentSyntax.GetExpression()); + } + + private IEnumerable GetExpressionsForAnalysys(SyntaxNodeAnalysisContext syntaxNodeContext, SyntaxNode syntax) + { + SyntaxNode body = null; + switch (syntax) + { + case SingleLineLambdaExpressionSyntax _: + case ExpressionStatementSyntax _: + case LocalDeclarationStatementSyntax _: + case AssignmentStatementSyntax _: + body = syntax; + break; + case MultiLineLambdaExpressionSyntax simpleLambdaExpressionSyntax: + foreach (var syntaxNode in IterateStatements(simpleLambdaExpressionSyntax.Statements)) + { + yield return syntaxNode; + } + + break; + case MethodBlockSyntax methodBlockSyntax: + foreach (var syntaxNode in IterateStatements(methodBlockSyntax.Statements)) + { + yield return syntaxNode; + } + + break; + case UnaryExpressionSyntax unaryExpressionSyntax: + foreach (var syntaxNode in GetExpressionsForAnalysys(syntaxNodeContext, unaryExpressionSyntax.Operand)) + { + yield return syntaxNode; + } + + break; + case IdentifierNameSyntax identifierNameSyntax: + var symbol = syntaxNodeContext.SemanticModel.GetSymbolInfo(identifierNameSyntax); + if (symbol.Symbol != null && symbol.Symbol.Locations.Any()) + { + var location = symbol.Symbol.Locations.First(); + var syntaxNode = location.SourceTree.GetRoot().FindNode(location.SourceSpan); + + SyntaxNode innerNode = null; + if (syntaxNode is MethodStatementSyntax methodStatementSyntax) + { + innerNode = methodStatementSyntax.Parent; + } + + innerNode = innerNode ?? syntaxNode; + foreach (var expressionsForAnalysy in GetExpressionsForAnalysys(syntaxNodeContext, innerNode)) + { + yield return expressionsForAnalysy; + } + } + + break; + } + + if (body == null) + { + yield break; + } + + var memberAccessExpressions = body.DescendantNodes().Where(node => node.IsKind(SyntaxKind.SimpleMemberAccessExpression)); + var invocationExpressions = body.DescendantNodes().Where(node => node.IsKind(SyntaxKind.InvocationExpression)); + + // rather ugly but prevents reporting two times the same thing + // as VB syntax is based on statements, you can't access body of method directly + if (invocationExpressions.Any()) + { + foreach (var invocationExpression in invocationExpressions) + { + yield return invocationExpression; + } + } + else if (memberAccessExpressions.Any()) + { + foreach (var memberAccessExpression in memberAccessExpressions) + { + yield return memberAccessExpression; + } + } + + IEnumerable IterateStatements(IEnumerable statements) + { + return statements.SelectMany(statement => GetExpressionsForAnalysys(syntaxNodeContext, statement)); + } + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/NSubstitute.Analyzers.VisualBasic.csproj b/src/NSubstitute.Analyzers.VisualBasic/NSubstitute.Analyzers.VisualBasic.csproj index da6ceb16..0d28a532 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/NSubstitute.Analyzers.VisualBasic.csproj +++ b/src/NSubstitute.Analyzers.VisualBasic/NSubstitute.Analyzers.VisualBasic.csproj @@ -1,6 +1,6 @@  - netstandard1.1 + netstandard1.3 portable45-net45+win8 false False @@ -22,7 +22,7 @@ - + diff --git a/src/NSubstitute.Analyzers.VisualBasic/Resources.Designer.cs b/src/NSubstitute.Analyzers.VisualBasic/Resources.Designer.cs index 35bfd125..ca6c8c8b 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/Resources.Designer.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/Resources.Designer.cs @@ -115,6 +115,33 @@ internal static string NonVirtualSetupSpecificationTitle { } } + /// + /// Looks up a localized string similar to Non-overridable members can not be intercepted.. + /// + internal static string NonVirtualWhenSetupSpecificationDescription { + get { + return ResourceManager.GetString("NonVirtualWhenSetupSpecificationDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Member {0} can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.. + /// + internal static string NonVirtualWhenSetupSpecificationMessageFormat { + get { + return ResourceManager.GetString("NonVirtualWhenSetupSpecificationMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Non-overridable setup specification. + /// + internal static string NonVirtualWhenSetupSpecificationTitle { + get { + return ResourceManager.GetString("NonVirtualWhenSetupSpecificationTitle", resourceCulture); + } + } + /// /// Looks up a localized string similar to Can not provide constructor arguments when substituting for a delegate.. /// diff --git a/src/NSubstitute.Analyzers.VisualBasic/Resources.resx b/src/NSubstitute.Analyzers.VisualBasic/Resources.resx index 85073a80..25f059a7 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/Resources.resx +++ b/src/NSubstitute.Analyzers.VisualBasic/Resources.resx @@ -260,5 +260,17 @@ Non-virtual setup specification. The title of the diagnostic. + + + Non-overridable members can not be intercepted. + An optional longer localizable description of the diagnostic. + + + Member {0} can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted. + The format-able message the diagnostic displays. + + + Non-overridable setup specification + The title of the diagnostic. diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/NonVirtualSetupWhenDiagnosticVerifier.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/NonVirtualSetupWhenDiagnosticVerifier.cs new file mode 100644 index 00000000..117caea2 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/NonVirtualSetupWhenDiagnosticVerifier.cs @@ -0,0 +1,61 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; + +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonVirtualSetupWhenAnalyzerTests +{ + public abstract class NonVirtualSetupWhenDiagnosticVerifier : CSharpDiagnosticVerifier, INonVirtualSetupWhenDiagnosticVerifier + { + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction); + + public abstract Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction); + + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction); + + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn); + + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InLocalFunction(); + + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InExpressionBodiedLocalFunction(); + + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction(); + + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularExpressionBodiedFunction(); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InLocalFunction(); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InExpressionBodiedLocalFunction(); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction(); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularExpressionBodiedFunction(); + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonVirtualSetupWhenAnalyzer(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsExtensionMethodTests.cs new file mode 100644 index 00000000..7f53f24a --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsExtensionMethodTests.cs @@ -0,0 +1,818 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenAsExtensionMethodTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("sub => sub.Bar()", 19, 36)] + [InlineData("delegate(Foo sub) { sub.Bar(); }", 19, 49)] + [InlineData("sub => { sub.Bar(); }", 19, 38)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub()")] + [InlineData("delegate(Func sub) { sub(); }")] + [InlineData("sub => { sub(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"using NSubstitute; +using System; + +namespace MyNamespace +{{ + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = Substitute.For>(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()", 24, 36)] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }", 24, 50)] + [InlineData("sub => { sub.Bar(); }", 24, 38)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public sealed override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("sub => { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For>(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub[1]; }")] + [InlineData("sub => { var x = sub[1]; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int this[int i] {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@" + +namespace NSubstitute +{{ + public class Foo + {{ + public int Bar() + {{ + return 1; + }} + }} + + public static class SubstituteExtensions + {{ + public static T When(this T substitute, System.Action substituteCall, int x) + {{ + return default(T); + }} + }} + + public class FooTests + {{ + public void Test() + {{ + Foo substitute = null; + substitute.When({whenAction}, 1); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }", 16, 46)] + [InlineData("sub => { int x; x = sub.Bar; }", 16, 49)] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }", 16, 57)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub[1]; }", 16, 46)] + [InlineData("delegate(Foo sub) { var x = sub[1]; }", 16, 57)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int this[int x] => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(22, 17) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(20, 45) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(26, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(24, 49) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsExtensionMethodWithGenericTypeSpecifiedTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsExtensionMethodWithGenericTypeSpecifiedTests.cs new file mode 100644 index 00000000..abf90726 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsExtensionMethodWithGenericTypeSpecifiedTests.cs @@ -0,0 +1,818 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenAsExtensionMethodWithGenericTypeSpecifiedTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("sub => sub.Bar()", 19, 41)] + [InlineData("delegate(Foo sub) { sub.Bar(); }", 19, 54)] + [InlineData("sub => { sub.Bar(); }", 19, 43)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub()")] + [InlineData("delegate(Func sub) { sub(); }")] + [InlineData("sub => { sub(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"using NSubstitute; +using System; + +namespace MyNamespace +{{ + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = Substitute.For>(); + substitute.When>({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()", 24, 42)] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }", 24, 56)] + [InlineData("sub => { sub.Bar(); }", 24, 44)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public sealed override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("sub => { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For>(); + substitute.When>({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub[1]; }")] + [InlineData("sub => { var x = sub[1]; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int this[int i] {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@" + +namespace NSubstitute +{{ + public class Foo + {{ + public int Bar() + {{ + return 1; + }} + }} + + public static class SubstituteExtensions + {{ + public static T When(this T substitute, System.Action substituteCall, int x) + {{ + return default(T); + }} + }} + + public class FooTests + {{ + public void Test() + {{ + Foo substitute = null; + substitute.When({whenAction}, 1); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }", 16, 51)] + [InlineData("sub => { int x; x = sub.Bar; }", 16, 54)] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }", 16, 62)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub[1]; }", 16, 51)] + [InlineData("delegate(Foo sub) { var x = sub[1]; }", 16, 62)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int this[int x] => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.When({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(22, 17) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(20, 45) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(26, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(24, 49) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.When(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..769dd06b --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs @@ -0,0 +1,818 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenAsOrdinaryMethodTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("sub => sub.Bar()", 19, 58)] + [InlineData("delegate(Foo sub) { sub.Bar(); }", 19, 71)] + [InlineData("sub => { sub.Bar(); }", 19, 60)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub()")] + [InlineData("delegate(Func sub) { sub(); }")] + [InlineData("sub => { sub(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"using NSubstitute; +using System; + +namespace MyNamespace +{{ + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = Substitute.For>(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()", 24, 58)] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }", 24, 72)] + [InlineData("sub => { sub.Bar(); }", 24, 60)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public sealed override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("sub => { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For>(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub[1]; }")] + [InlineData("sub => { var x = sub[1]; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int this[int i] {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@" + +namespace NSubstitute +{{ + public class Foo + {{ + public int Bar() + {{ + return 1; + }} + }} + + public static class SubstituteExtensions + {{ + public static T When(this T substitute, System.Action substituteCall, int x) + {{ + return default(T); + }} + }} + + public class FooTests + {{ + public void Test() + {{ + Foo substitute = null; + SubstituteExtensions.When(substitute, {whenAction}, 1); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }", 16, 68)] + [InlineData("sub => { int x; x = sub.Bar; }", 16, 71)] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }", 16, 79)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub[1]; }", 16, 68)] + [InlineData("delegate(Foo sub) { var x = sub[1]; }", 16, 79)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int this[int x] => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(22, 17) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(20, 45) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(26, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(24, 49) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs new file mode 100644 index 00000000..1e8bc606 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs @@ -0,0 +1,818 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenAsOrdinaryMethodWithGenericTypeSpecifiedTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("sub => sub.Bar()", 19, 63)] + [InlineData("delegate(Foo sub) { sub.Bar(); }", 19, 76)] + [InlineData("sub => { sub.Bar(); }", 19, 65)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub()")] + [InlineData("delegate(Func sub) { sub(); }")] + [InlineData("sub => { sub(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"using NSubstitute; +using System; + +namespace MyNamespace +{{ + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = Substitute.For>(); + SubstituteExtensions.When>(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()", 24, 64)] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }", 24, 78)] + [InlineData("sub => { sub.Bar(); }", 24, 66)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public sealed override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("sub => { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For>(); + SubstituteExtensions.When>(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub[1]; }")] + [InlineData("sub => { var x = sub[1]; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int this[int i] {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@" + +namespace NSubstitute +{{ + public class Foo + {{ + public int Bar() + {{ + return 1; + }} + }} + + public static class SubstituteExtensions + {{ + public static T When(this T substitute, System.Action substituteCall, int x) + {{ + return default(T); + }} + }} + + public class FooTests + {{ + public void Test() + {{ + Foo substitute = null; + SubstituteExtensions.When(substitute, {whenAction}, 1); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }", 16, 73)] + [InlineData("sub => { int x; x = sub.Bar; }", 16, 76)] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }", 16, 84)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub[1]; }", 16, 73)] + [InlineData("delegate(Foo sub) { var x = sub[1]; }", 16, 84)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int this[int x] => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.When(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(22, 17) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(20, 45) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(26, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(24, 49) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.When(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsExtensionMethodTests.cs new file mode 100644 index 00000000..83a69161 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsExtensionMethodTests.cs @@ -0,0 +1,818 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenForAnyArgsAsExtensionMethodTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("sub => sub.Bar()", 19, 46)] + [InlineData("delegate(Foo sub) { sub.Bar(); }", 19, 59)] + [InlineData("sub => { sub.Bar(); }", 19, 48)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub()")] + [InlineData("delegate(Func sub) { sub(); }")] + [InlineData("sub => { sub(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"using NSubstitute; +using System; + +namespace MyNamespace +{{ + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = Substitute.For>(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()", 24, 46)] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }", 24, 60)] + [InlineData("sub => { sub.Bar(); }", 24, 48)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public sealed override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("sub => { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For>(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub[1]; }")] + [InlineData("sub => { var x = sub[1]; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int this[int i] {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@" + +namespace NSubstitute +{{ + public class Foo + {{ + public int Bar() + {{ + return 1; + }} + }} + + public static class SubstituteExtensions + {{ + public static T WhenForAnyArgs(this T substitute, System.Action substituteCall, int x) + {{ + return default(T); + }} + }} + + public class FooTests + {{ + public void Test() + {{ + Foo substitute = null; + substitute.WhenForAnyArgs({whenAction}, 1); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }", 16, 56)] + [InlineData("sub => { int x; x = sub.Bar; }", 16, 59)] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }", 16, 67)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub[1]; }", 16, 56)] + [InlineData("delegate(Foo sub) { var x = sub[1]; }", 16, 67)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int this[int x] => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(22, 17) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(20, 45) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(26, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(24, 49) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsExtensionMethodWithGenericTypeSpecifiedTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsExtensionMethodWithGenericTypeSpecifiedTests.cs new file mode 100644 index 00000000..6a454b6b --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsExtensionMethodWithGenericTypeSpecifiedTests.cs @@ -0,0 +1,818 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenForAnyArgsAsExtensionMethodWithGenericTypeSpecifiedTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("sub => sub.Bar()", 19, 51)] + [InlineData("delegate(Foo sub) { sub.Bar(); }", 19, 64)] + [InlineData("sub => { sub.Bar(); }", 19, 53)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub()")] + [InlineData("delegate(Func sub) { sub(); }")] + [InlineData("sub => { sub(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"using NSubstitute; +using System; + +namespace MyNamespace +{{ + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = Substitute.For>(); + substitute.WhenForAnyArgs>({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()", 24, 52)] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }", 24, 66)] + [InlineData("sub => { sub.Bar(); }", 24, 54)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public sealed override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("sub => { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For>(); + substitute.WhenForAnyArgs>({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub[1]; }")] + [InlineData("sub => { var x = sub[1]; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int this[int i] {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@" + +namespace NSubstitute +{{ + public class Foo + {{ + public int Bar() + {{ + return 1; + }} + }} + + public static class SubstituteExtensions + {{ + public static T WhenForAnyArgs(this T substitute, System.Action substituteCall, int x) + {{ + return default(T); + }} + }} + + public class FooTests + {{ + public void Test() + {{ + Foo substitute = null; + substitute.WhenForAnyArgs({whenAction}, 1); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }", 16, 61)] + [InlineData("sub => { int x; x = sub.Bar; }", 16, 64)] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }", 16, 72)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub[1]; }", 16, 61)] + [InlineData("delegate(Foo sub) { var x = sub[1]; }", 16, 72)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int this[int x] => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + substitute.WhenForAnyArgs({whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(22, 17) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(20, 45) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(26, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(24, 49) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + substitute.WhenForAnyArgs(SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..7dd2a5d0 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodTests.cs @@ -0,0 +1,818 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenForAnyArgsAsOrdinaryMethodTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("sub => sub.Bar()", 19, 68)] + [InlineData("delegate(Foo sub) { sub.Bar(); }", 19, 81)] + [InlineData("sub => { sub.Bar(); }", 19, 70)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub()")] + [InlineData("delegate(Func sub) { sub(); }")] + [InlineData("sub => { sub(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"using NSubstitute; +using System; + +namespace MyNamespace +{{ + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = Substitute.For>(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()", 24, 68)] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }", 24, 82)] + [InlineData("sub => { sub.Bar(); }", 24, 70)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public sealed override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("sub => { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For>(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub[1]; }")] + [InlineData("sub => { var x = sub[1]; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int this[int i] {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@" + +namespace NSubstitute +{{ + public class Foo + {{ + public int Bar() + {{ + return 1; + }} + }} + + public static class SubstituteExtensions + {{ + public static T WhenForAnyArgs(this T substitute, System.Action substituteCall, int x) + {{ + return default(T); + }} + }} + + public class FooTests + {{ + public void Test() + {{ + Foo substitute = null; + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}, 1); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }", 16, 78)] + [InlineData("sub => { int x; x = sub.Bar; }", 16, 81)] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }", 16, 89)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub[1]; }", 16, 78)] + [InlineData("delegate(Foo sub) { var x = sub[1]; }", 16, 89)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int this[int x] => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(22, 17) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(20, 45) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(26, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(24, 49) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs new file mode 100644 index 00000000..04730662 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/DiagnosticAnalyzerTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs @@ -0,0 +1,818 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenForAnyArgsAsOrdinaryMethodWithGenericTypeSpecifiedTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("sub => sub.Bar()", 19, 73)] + [InlineData("delegate(Foo sub) { sub.Bar(); }", 19, 86)] + [InlineData("sub => { sub.Bar(); }", 19, 75)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub()")] + [InlineData("delegate(Func sub) { sub(); }")] + [InlineData("sub => { sub(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"using NSubstitute; +using System; + +namespace MyNamespace +{{ + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = Substitute.For>(); + SubstituteExtensions.WhenForAnyArgs>(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()", 24, 74)] + [InlineData("delegate(Foo2 sub) { sub.Bar(); }", 24, 88)] + [InlineData("sub => { sub.Bar(); }", 24, 76)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 2; + }} + }} + + public class Foo2 : Foo + {{ + public sealed override int Bar() => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("sub => { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(IFoo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int Bar(); + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For>(); + SubstituteExtensions.WhenForAnyArgs>(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public abstract class Foo + {{ + public abstract int Bar {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("delegate(IFoo sub) { var x = sub[1]; }")] + [InlineData("sub => { var x = sub[1]; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public interface IFoo + {{ + int this[int i] {{ get; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => sub.Bar()")] + [InlineData("delegate(Foo sub) { sub.Bar(); }")] + [InlineData("sub => { sub.Bar(); }")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@" + +namespace NSubstitute +{{ + public class Foo + {{ + public int Bar() + {{ + return 1; + }} + }} + + public static class SubstituteExtensions + {{ + public static T WhenForAnyArgs(this T substitute, System.Action substituteCall, int x) + {{ + return default(T); + }} + }} + + public class FooTests + {{ + public void Test() + {{ + Foo substitute = null; + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}, 1); + }} + }} +}}"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }", 16, 83)] + [InlineData("sub => { int x; x = sub.Bar; }", 16, 86)] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }", 16, 94)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("sub => { var x = sub.Bar; }")] + [InlineData("sub => { int x; x = sub.Bar; }")] + [InlineData("delegate(Foo sub) { var x = sub.Bar; }")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar {{get; set; }} + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("sub => { var x = sub[1]; }", 16, 83)] + [InlineData("delegate(Foo sub) { var x = sub[1]; }", 16, 94)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"using NSubstitute; + +namespace MyNamespace +{{ + public class Foo + {{ + public int this[int x] => 1; + }} + + public class FooTests + {{ + public void Test() + {{ + int i = 1; + var substitute = NSubstitute.Substitute.For(); + SubstituteExtensions.WhenForAnyArgs(substitute, {whenAction}).Do(callInfo => i++); + }} + }} +}}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member this[] can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(22, 17) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(20, 45) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(26, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and virtual, overriding, and abstract members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(24, 49) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) + { + sub.Bar(); + } + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InExpressionBodiedLocalFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + void SubstituteCall(Foo sub) => sub.Bar(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) + { + var objBarr = sub.Bar(); + } + } +}"; + await VerifyDiagnostic(source); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularExpressionBodiedFunction() + { + var source = @"using NSubstitute; + +namespace MyNamespace +{ + public class Foo + { + public virtual int Bar() + { + return 2; + } + } + + public class FooTests + { + public void Test() + { + int i = 0; + var substitute = NSubstitute.Substitute.For(); + + SubstituteExtensions.WhenForAnyArgs(substitute, SubstituteCall).Do(callInfo => i++); + substitute.Bar(); + } + + private void SubstituteCall(Foo sub) => sub.Bar(); + } +}"; + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/INonVirtualSetupWhenDiagnosticVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/INonVirtualSetupWhenDiagnosticVerifier.cs new file mode 100644 index 00000000..d698cedb --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.Shared/DiagnosticAnalyzers/INonVirtualSetupWhenDiagnosticVerifier.cs @@ -0,0 +1,41 @@ +using System.Threading.Tasks; + +namespace NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers +{ + public interface INonVirtualSetupWhenDiagnosticVerifier + { + Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn); + + Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction); + + Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction); + + Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction); + + Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn); + + Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction); + + Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction); + + Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction); + + Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction); + + Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction); + + Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction); + + Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction); + + Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn); + + Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction); + + Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn); + + Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction(); + + Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction(); + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupAnalyzerTests/ReturnsForAnyArgsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupAnalyzerTests/ReturnsForAnyArgsAsExtensionMethodTests.cs index 30158840..402a2037 100644 --- a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupAnalyzerTests/ReturnsForAnyArgsAsExtensionMethodTests.cs +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupAnalyzerTests/ReturnsForAnyArgsAsExtensionMethodTests.cs @@ -1,7 +1,6 @@ using System.Threading.Tasks; using Microsoft.CodeAnalysis; using NSubstitute.Analyzers.Shared; -using NSubstitute.Analyzers.Tests.Shared; using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonVirtualSetupAnalyzerTests diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/NonVirtualSetupWhenDiagnosticVerifier.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/NonVirtualSetupWhenDiagnosticVerifier.cs new file mode 100644 index 00000000..77c6e1ec --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/NonVirtualSetupWhenDiagnosticVerifier.cs @@ -0,0 +1,49 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonVirtualSetupWhenAnalyzerTests +{ + public abstract class NonVirtualSetupWhenDiagnosticVerifier : VisualBasicDiagnosticVerifier, INonVirtualSetupWhenDiagnosticVerifier + { + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction); + + public abstract Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction); + + public abstract Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction); + + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction); + + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn); + + public abstract Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction(); + + public abstract Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction(); + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonVirtualSetupWhenAnalyzer(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenAsExtensionMethodTests.cs new file mode 100644 index 00000000..5502a18b --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenAsExtensionMethodTests.cs @@ -0,0 +1,610 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenAsExtensionMethodTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("Sub(sb) sb.Bar()", 14, 39)] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()", 14, 60)] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub", + 15, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb()")] + [InlineData(@"Function(ByVal [sub] As Func(Of Integer)) [sub]()")] + [InlineData( + @"Sub(sb As Func(Of Integer)) + sb() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"Imports NSubstitute +Imports System + +Namespace MyNamespace + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Func(Of Integer))() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()", 22, 39)] + [InlineData(@"Function(ByVal [sub] As Foo2) [sub].Bar()", 22, 61)] + [InlineData( + @"Sub(sb As Foo2) + sb.Bar() + End Sub", + 23, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public NotOverridable Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride Function Bar() As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As IFoo) [sub].Bar()")] + [InlineData( + @"Sub(sb As IFoo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Function Bar() As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As IFoo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + ReadOnly Property Bar As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar(Of Integer)()")] + [InlineData(@"Function(ByVal [sub] As IFoo(Of Integer)) [sub].Bar(Of Integer)()")] + [InlineData( + @"Sub(sb As IFoo(Of Integer)) + sb.Bar(Of Integer)() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + + Public Interface IFoo(Of T) + + Function Bar(Of T)() As Integer + End Interface + + Public Class FooTests + + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo (Of Integer))() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb(1) + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Default Property Item(ByVal i As Integer) As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@"Imports System.Runtime.CompilerServices + +Namespace NSubstitute + Public Class Foo + Public Function Bar() As Integer + Return 1 + End Function + End Class + + Module SubstituteExtensions + + Function [When](Of T)(ByVal substitute As T, ByVal substituteCall As System.Action(Of T), ByVal x As Integer) As T + Return Nothing + End Function + End Module + + Public Class FooTests + Public Sub Test() + Dim substitute As Foo = Nothing + substitute.[When]({whenAction}, 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub", + 13, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub", + 14, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public Overridable Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb(1) + End Sub", + 19, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb(1) + End Sub", + 20, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + + Public Default ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Throw New System.NotImplementedException + End Get + End Property + End Class + + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.[When]({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.[When](AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(19, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.[When](AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..3f9bfa41 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodTests.cs @@ -0,0 +1,610 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenAsOrdinaryMethodTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("Sub(sb) sb.Bar()", 14, 58)] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()", 14, 79)] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub", + 15, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb()")] + [InlineData(@"Function(ByVal [sub] As Func(Of Integer)) [sub]()")] + [InlineData( + @"Sub(sb As Func(Of Integer)) + sb() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"Imports NSubstitute +Imports System + +Namespace MyNamespace + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Func(Of Integer))() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()", 22, 58)] + [InlineData(@"Function(ByVal [sub] As Foo2) [sub].Bar()", 22, 80)] + [InlineData( + @"Sub(sb As Foo2) + sb.Bar() + End Sub", + 23, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public NotOverridable Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride Function Bar() As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As IFoo) [sub].Bar()")] + [InlineData( + @"Sub(sb As IFoo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Function Bar() As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As IFoo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + ReadOnly Property Bar As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar(Of Integer)()")] + [InlineData(@"Function(ByVal [sub] As IFoo(Of Integer)) [sub].Bar(Of Integer)()")] + [InlineData( + @"Sub(sb As IFoo(Of Integer)) + sb.Bar(Of Integer)() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + + Public Interface IFoo(Of T) + + Function Bar(Of T)() As Integer + End Interface + + Public Class FooTests + + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo (Of Integer))() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb(1) + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Default Property Item(ByVal i As Integer) As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@"Imports System.Runtime.CompilerServices + +Namespace NSubstitute + Public Class Foo + Public Function Bar() As Integer + Return 1 + End Function + End Class + + Module SubstituteExtensions + + Function [When](Of T)(ByVal substitute As T, ByVal substituteCall As System.Action(Of T), ByVal x As Integer) As T + Return Nothing + End Function + End Module + + Public Class FooTests + Public Sub Test() + Dim substitute As Foo = Nothing + SubstituteExtensions.[When](substitute, {whenAction}, 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub", + 13, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub", + 14, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public Overridable Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb(1) + End Sub", + 19, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb(1) + End Sub", + 20, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + + Public Default ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Throw New System.NotImplementedException + End Get + End Property + End Class + + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(substitute,AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(19, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(substitute,AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs new file mode 100644 index 00000000..0e9723ad --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs @@ -0,0 +1,610 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenAsOrdinaryMethodWithGenericTypeSpecifiedTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("Sub(sb) sb.Bar()", 14, 66)] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()", 14, 87)] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub", + 15, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + SubstituteExtensions.When(Of Foo2)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb()")] + [InlineData(@"Function(ByVal [sub] As Func(Of Integer)) [sub]()")] + [InlineData( + @"Sub(sb As Func(Of Integer)) + sb() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"Imports NSubstitute +Imports System + +Namespace MyNamespace + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Func(Of Integer))() + SubstituteExtensions.When(Of Func(Of Integer))(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()", 22, 67)] + [InlineData(@"Function(ByVal [sub] As Foo2) [sub].Bar()", 22, 89)] + [InlineData( + @"Sub(sb As Foo2) + sb.Bar() + End Sub", + 23, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public NotOverridable Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + SubstituteExtensions.When(Of Foo2)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride Function Bar() As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As IFoo) [sub].Bar()")] + [InlineData( + @"Sub(sb As IFoo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Function Bar() As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.When(Of IFoo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As IFoo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + ReadOnly Property Bar As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.When(Of IFoo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar(Of Integer)()")] + [InlineData(@"Function(ByVal [sub] As IFoo(Of Integer)) [sub].Bar(Of Integer)()")] + [InlineData( + @"Sub(sb As IFoo(Of Integer)) + sb.Bar(Of Integer)() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + + Public Interface IFoo(Of T) + + Function Bar(Of T)() As Integer + End Interface + + Public Class FooTests + + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo (Of Integer))() + SubstituteExtensions.When(Of IFoo (Of Integer))(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb(1) + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Default Property Item(ByVal i As Integer) As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.When(Of IFoo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@"Imports System.Runtime.CompilerServices + +Namespace NSubstitute + Public Class Foo + Public Function Bar() As Integer + Return 1 + End Function + End Class + + Module SubstituteExtensions + + Function [When](Of T)(ByVal substitute As T, ByVal substituteCall As System.Action(Of T), ByVal x As Integer) As T + Return Nothing + End Function + End Module + + Public Class FooTests + Public Sub Test() + Dim substitute As Foo = Nothing + SubstituteExtensions.[When](Of Foo)(substitute, {whenAction}, 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub", + 13, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub", + 14, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public Overridable Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb(1) + End Sub", + 19, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb(1) + End Sub", + 20, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + + Public Default ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Throw New System.NotImplementedException + End Get + End Property + End Class + + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(Of Foo)(substitute,AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(19, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.When(Of Foo)(substitute,AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsExtensionMethodTests.cs new file mode 100644 index 00000000..2a783a30 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsExtensionMethodTests.cs @@ -0,0 +1,610 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenForAnyArgsAsExtensionMethodTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("Sub(sb) sb.Bar()", 14, 47)] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()", 14, 68)] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub", + 15, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb()")] + [InlineData(@"Function(ByVal [sub] As Func(Of Integer)) [sub]()")] + [InlineData( + @"Sub(sb As Func(Of Integer)) + sb() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"Imports NSubstitute +Imports System + +Namespace MyNamespace + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Func(Of Integer))() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()", 22, 47)] + [InlineData(@"Function(ByVal [sub] As Foo2) [sub].Bar()", 22, 69)] + [InlineData( + @"Sub(sb As Foo2) + sb.Bar() + End Sub", + 23, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public NotOverridable Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride Function Bar() As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As IFoo) [sub].Bar()")] + [InlineData( + @"Sub(sb As IFoo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Function Bar() As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As IFoo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + ReadOnly Property Bar As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar(Of Integer)()")] + [InlineData(@"Function(ByVal [sub] As IFoo(Of Integer)) [sub].Bar(Of Integer)()")] + [InlineData( + @"Sub(sb As IFoo(Of Integer)) + sb.Bar(Of Integer)() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + + Public Interface IFoo(Of T) + + Function Bar(Of T)() As Integer + End Interface + + Public Class FooTests + + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo (Of Integer))() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb(1) + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Default Property Item(ByVal i As Integer) As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@"Imports System.Runtime.CompilerServices + +Namespace NSubstitute + Public Class Foo + Public Function Bar() As Integer + Return 1 + End Function + End Class + + Module SubstituteExtensions + + Function WhenForAnyArgs(Of T)(ByVal substitute As T, ByVal substituteCall As System.Action(Of T), ByVal x As Integer) As T + Return Nothing + End Function + End Module + + Public Class FooTests + Public Sub Test() + Dim substitute As Foo = Nothing + substitute.WhenForAnyArgs({whenAction}, 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub", + 13, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub", + 14, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public Overridable Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb(1) + End Sub", + 19, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb(1) + End Sub", + 20, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + + Public Default ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Throw New System.NotImplementedException + End Get + End Property + End Class + + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.WhenForAnyArgs({whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.WhenForAnyArgs(AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(19, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.WhenForAnyArgs(AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..8540c4fc --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodTests.cs @@ -0,0 +1,610 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenForAnyArgsAsOrdinaryMethodTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("Sub(sb) sb.Bar()", 14, 68)] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()", 14, 89)] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub", + 15, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb()")] + [InlineData(@"Function(ByVal [sub] As Func(Of Integer)) [sub]()")] + [InlineData( + @"Sub(sb As Func(Of Integer)) + sb() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"Imports NSubstitute +Imports System + +Namespace MyNamespace + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Func(Of Integer))() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()", 22, 68)] + [InlineData(@"Function(ByVal [sub] As Foo2) [sub].Bar()", 22, 90)] + [InlineData( + @"Sub(sb As Foo2) + sb.Bar() + End Sub", + 23, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public NotOverridable Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride Function Bar() As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As IFoo) [sub].Bar()")] + [InlineData( + @"Sub(sb As IFoo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Function Bar() As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As IFoo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + ReadOnly Property Bar As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar(Of Integer)()")] + [InlineData(@"Function(ByVal [sub] As IFoo(Of Integer)) [sub].Bar(Of Integer)()")] + [InlineData( + @"Sub(sb As IFoo(Of Integer)) + sb.Bar(Of Integer)() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + + Public Interface IFoo(Of T) + + Function Bar(Of T)() As Integer + End Interface + + Public Class FooTests + + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo (Of Integer))() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb(1) + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Default Property Item(ByVal i As Integer) As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@"Imports System.Runtime.CompilerServices + +Namespace NSubstitute + Public Class Foo + Public Function Bar() As Integer + Return 1 + End Function + End Class + + Module SubstituteExtensions + + Function [WhenForAnyArgs](Of T)(ByVal substitute As T, ByVal substituteCall As System.Action(Of T), ByVal x As Integer) As T + Return Nothing + End Function + End Module + + Public Class FooTests + Public Sub Test() + Dim substitute As Foo = Nothing + SubstituteExtensions.[WhenForAnyArgs](substitute, {whenAction}, 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub", + 13, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub", + 14, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public Overridable Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb(1) + End Sub", + 19, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb(1) + End Sub", + 20, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + + Public Default ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Throw New System.NotImplementedException + End Get + End Property + End Class + + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(substitute,AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(19, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(substitute,AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs new file mode 100644 index 00000000..6c271e03 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/DiagnosticAnalyzersTests/NonVirtualSetupWhenAnalyzerTests/WhenForAnyArgsAsOrdinaryMethodWithGenericTypeSpecifiedTests.cs @@ -0,0 +1,610 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using NSubstitute.Analyzers.Shared; +using NSubstitute.Analyzers.Tests.Shared.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonVirtualSetupWhenAnalyzerTests +{ + public class WhenForAnyArgsAsOrdinaryMethodWithGenericTypeSpecifiedTests : NonVirtualSetupWhenDiagnosticVerifier + { + [Theory] + [InlineData("Sub(sb) sb.Bar()", 14, 76)] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()", 14, 97)] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub", + 15, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForNonSealedOverrideMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + SubstituteExtensions.WhenForAnyArgs(Of Foo2)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb()")] + [InlineData(@"Function(ByVal [sub] As Func(Of Integer)) [sub]()")] + [InlineData( + @"Sub(sb As Func(Of Integer)) + sb() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForDelegate(string whenAction) + { + var source = $@"Imports NSubstitute +Imports System + +Namespace MyNamespace + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Func(Of Integer))() + SubstituteExtensions.WhenForAnyArgs(Of Func(Of Integer))(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()", 22, 77)] + [InlineData(@"Function(ByVal [sub] As Foo2) [sub].Bar()", 22, 99)] + [InlineData( + @"Sub(sb As Foo2) + sb.Bar() + End Sub", + 23, + 17)] + public override async Task ReportsDiagnostics_WhenSettingValueForSealedOverrideMethod(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class Foo2 + Inherits Foo + + Public NotOverridable Overrides Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo2)() + SubstituteExtensions.WhenForAnyArgs(Of Foo2)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride Function Bar() As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As IFoo) [sub].Bar()")] + [InlineData( + @"Sub(sb As IFoo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Function Bar() As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.WhenForAnyArgs(Of IFoo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i +1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As IFoo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + ReadOnly Property Bar As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.WhenForAnyArgs(Of IFoo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar(Of Integer)()")] + [InlineData(@"Function(ByVal [sub] As IFoo(Of Integer)) [sub].Bar(Of Integer)()")] + [InlineData( + @"Sub(sb As IFoo(Of Integer)) + sb.Bar(Of Integer)() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForGenericInterfaceMethod(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + + Public Interface IFoo(Of T) + + Function Bar(Of T)() As Integer + End Interface + + Public Class FooTests + + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo (Of Integer))() + SubstituteExtensions.WhenForAnyArgs(Of IFoo (Of Integer))(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForAbstractProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public MustOverride ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As IFoo) + Dim x = sb(1) + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForInterfaceIndexer(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Interface IFoo + Default Property Item(ByVal i As Integer) As Integer + End Interface + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of IFoo)() + SubstituteExtensions.WhenForAnyArgs(Of IFoo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData("Sub(sb) sb.Bar()")] + [InlineData(@"Function(ByVal [sub] As Foo) [sub].Bar()")] + [InlineData( + @"Sub(sb As Foo) + sb.Bar() + End Sub")] + public override async Task ReportsNoDiagnostics_WhenUsingUnfortunatelyNamedMethod(string whenAction) + { + var source = $@"Imports System.Runtime.CompilerServices + +Namespace NSubstitute + Public Class Foo + Public Function Bar() As Integer + Return 1 + End Function + End Class + + Module SubstituteExtensions + + Function [WhenForAnyArgs](Of T)(ByVal substitute As T, ByVal substituteCall As System.Action(Of T), ByVal x As Integer) As T + Return Nothing + End Function + End Module + + Public Class FooTests + Public Sub Test() + Dim substitute As Foo = Nothing + SubstituteExtensions.[WhenForAnyArgs](Of Foo)(substitute, {whenAction}, 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub", + 13, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub", + 14, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualProperty(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public ReadOnly Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb.Bar + End Sub")] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb.Bar + End Sub")] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualProperty(string whenAction) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public MustInherit Class Foo + Public Overridable Property Bar As Integer + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + await VerifyDiagnostic(source); + } + + [Theory] + [InlineData( + @"Sub(sb As Foo) + Dim x = sb(1) + End Sub", + 19, + 25)] + [InlineData( + @"Sub(sb As Foo) + Dim x as Integer + x = sb(1) + End Sub", + 20, + 21)] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualIndexer(string whenAction, int expectedLine, int expectedColumn) + { + var source = $@"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + + Public Default ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Throw New System.NotImplementedException + End Get + End Property + End Class + + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 1 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(Of Foo)(substitute,{whenAction}).[Do](Sub(callInfo) i = i + 1) + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Item can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(expectedLine, expectedColumn) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsDiagnostics_WhenSettingValueForNonVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(Of Foo)(substitute,AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + var expectedDiagnostic = new DiagnosticResult + { + Id = DiagnosticIdentifiers.NonVirtualWhenSetupSpecification, + Severity = DiagnosticSeverity.Warning, + Message = "Member Bar can not be intercepted. Only interface members and overrideable, overriding, and must override members can be intercepted.", + Locations = new[] + { + new DiagnosticResultLocation(19, 27) + } + }; + + await VerifyDiagnostic(source, expectedDiagnostic); + } + + [Fact] + public override async Task ReportsNoDiagnostics_WhenSettingValueForVirtualMember_InRegularFunction() + { + var source = @"Imports NSubstitute + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 2 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim i As Integer = 0 + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + SubstituteExtensions.WhenForAnyArgs(Of Foo)(substitute,AddressOf SubstituteCall).[Do](Sub(callInfo) i = i + 1) + substitute.Bar() + End Sub + + Private Sub SubstituteCall(ByVal [sub] As Foo) + Dim objBarr = [sub].Bar() + End Sub + End Class +End Namespace +"; + + await VerifyDiagnostic(source); + } + } +} \ No newline at end of file