diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs new file mode 100644 index 00000000..2795bd87 --- /dev/null +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using NSubstitute.Analyzers.CSharp.Refactorings; +using NSubstitute.Analyzers.Shared.CodeFixProviders; + +namespace NSubstitute.Analyzers.CSharp.CodeFixProviders +{ + [ExportCodeFixProvider(LanguageNames.CSharp)] + internal class InternalSetupSpecificationCodeFixProvider : AbstractInternalSetupSpecificationCodeFixProvider + { + protected override string ReplaceModifierCodeFixTitle { get; } = "Replace internal with public modifier"; + + protected override Task AddModifierRefactoring(Document document, SyntaxNode node, Accessibility accessibility) + { + return Refactorings.AddModifierRefactoring.RefactorAsync(document, node, accessibility); + } + + protected override Task ReplaceModifierRefactoring(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility) + { + return Refactorings.ReplaceModifierRefactoring.RefactorAsync(document, node, fromAccessibility, toAccessibility); + } + + protected override void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + { + AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, diagnostic, compilationUnitSyntax); + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs index dd92a736..9ab3be2a 100644 --- a/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.CSharp/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs @@ -3,6 +3,7 @@ using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; +using NSubstitute.Analyzers.CSharp.Refactorings; using NSubstitute.Analyzers.Shared.CodeFixProviders; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; @@ -17,27 +18,9 @@ protected override AbstractSubstituteProxyAnalysistrue Properties $(VersionSuffix) + latest NSubstitute.Analyzers.CSharp diff --git a/src/NSubstitute.Analyzers.CSharp/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs new file mode 100644 index 00000000..d95f30e0 --- /dev/null +++ b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs @@ -0,0 +1,50 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using NSubstitute.Analyzers.Shared.Extensions; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace NSubstitute.Analyzers.CSharp.Refactorings +{ + internal static class AddInternalsVisibleToAttributeRefactoring + { + public static Task RefactorAsync(Document document, CompilationUnitSyntax compilationUnitSyntax, CancellationToken cancellationToken = default) + { + var addAttributeLists = compilationUnitSyntax.AddAttributeLists( + AttributeList( + AttributeTargetSpecifier( + Token(SyntaxKind.AssemblyKeyword)), + SingletonSeparatedList( + Attribute( + QualifiedName( + QualifiedName( + QualifiedName( + IdentifierName("System"), + IdentifierName("Runtime")), + IdentifierName("CompilerServices")), + IdentifierName("InternalsVisibleTo")), + AttributeArgumentList( + SingletonSeparatedList( + AttributeArgument( + LiteralExpression( + SyntaxKind.StringLiteralExpression, + Literal("DynamicProxyGenAssembly2"))))))))); + + return document.ReplaceNodeAsync(compilationUnitSyntax, addAttributeLists, CancellationToken.None); + } + + public static void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + { + var codeAction = CodeAction.Create( + "Add InternalsVisibleTo attribute", + cancellationToken => RefactorAsync(context.Document, compilationUnitSyntax, cancellationToken), + diagnostic.Id); + + context.RegisterCodeFix(codeAction, context.Diagnostics); + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs new file mode 100644 index 00000000..6242d6d9 --- /dev/null +++ b/src/NSubstitute.Analyzers.CSharp/Refactorings/AddModifierRefactoring.cs @@ -0,0 +1,51 @@ +using System; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using NSubstitute.Analyzers.Shared.Extensions; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace NSubstitute.Analyzers.CSharp.Refactorings +{ + internal static class AddModifierRefactoring + { + public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility accessibility) + { + SyntaxKind syntaxKind; + + switch (accessibility) + { + case Accessibility.Protected: + syntaxKind = SyntaxKind.ProtectedKeyword; + break; + default: + throw new NotSupportedException($"Adding {accessibility} modifier is not supported"); + } + + var newNode = Insert(node, syntaxKind); + + return document.ReplaceNodeAsync(node, newNode); + } + + private static SyntaxNode Insert(SyntaxNode node, SyntaxKind syntaxKind) + { + switch (node) + { + case MethodDeclarationSyntax methodDeclarationSyntax: + return methodDeclarationSyntax.WithModifiers(UpdateModifiers(methodDeclarationSyntax.Modifiers, syntaxKind)); + case PropertyDeclarationSyntax propertyDeclarationSyntax: + return propertyDeclarationSyntax.WithModifiers(UpdateModifiers(propertyDeclarationSyntax.Modifiers, syntaxKind)); + case IndexerDeclarationSyntax indexerDeclarationSyntax: + return indexerDeclarationSyntax.WithModifiers(UpdateModifiers(indexerDeclarationSyntax.Modifiers, syntaxKind)); + default: + throw new NotSupportedException($"Adding {syntaxKind} to {node.Kind()} is not supported"); + } + } + + private static SyntaxTokenList UpdateModifiers(SyntaxTokenList modifiers, SyntaxKind modifier) + { + return modifiers.Any(modifier) ? modifiers : modifiers.Insert(0, Token(modifier)); + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs b/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs new file mode 100644 index 00000000..774fb5ef --- /dev/null +++ b/src/NSubstitute.Analyzers.CSharp/Refactorings/ReplaceModifierRefactoring.cs @@ -0,0 +1,63 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using NSubstitute.Analyzers.Shared.Extensions; +using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; + +namespace NSubstitute.Analyzers.CSharp.Refactorings +{ + internal class ReplaceModifierRefactoring + { + public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility) + { + var fromSyntaxKind = InferSyntaxKind(fromAccessibility); + var toSyntaxKind = InferSyntaxKind(toAccessibility); + + var newNode = ReplaceModifier(node, fromSyntaxKind, toSyntaxKind); + + return document.ReplaceNodeAsync(node, newNode); + } + + private static SyntaxKind InferSyntaxKind(Accessibility fromAccessibility) + { + SyntaxKind syntaxKind; + switch (fromAccessibility) + { + case Accessibility.Internal: + syntaxKind = SyntaxKind.InternalKeyword; + break; + case Accessibility.Public: + syntaxKind = SyntaxKind.PublicKeyword; + break; + default: + throw new NotSupportedException($"Replacing {fromAccessibility} modifier is not supported"); + } + + return syntaxKind; + } + + private static SyntaxNode ReplaceModifier(SyntaxNode node, SyntaxKind fromSyntaxKind, SyntaxKind toSyntaxKind) + { + switch (node) + { + case MethodDeclarationSyntax methodDeclarationSyntax: + return methodDeclarationSyntax.WithModifiers(ReplaceModifier(methodDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); + case PropertyDeclarationSyntax propertyDeclarationSyntax: + return propertyDeclarationSyntax.WithModifiers(ReplaceModifier(propertyDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); + case IndexerDeclarationSyntax indexerDeclarationSyntax: + return indexerDeclarationSyntax.WithModifiers(ReplaceModifier(indexerDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); + default: + throw new NotSupportedException($"Replacing {fromSyntaxKind} in {node.Kind()} is not supported"); + } + } + + private static SyntaxTokenList ReplaceModifier(SyntaxTokenList modifiers, SyntaxKind fromModifier, SyntaxKind toModifier) + { + var modifier = modifiers.First(mod => mod.IsKind(fromModifier)); + return modifiers.Replace(modifier, Token(toModifier)); + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs new file mode 100644 index 00000000..b3b2e419 --- /dev/null +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractInternalSetupSpecificationCodeFixProvider.cs @@ -0,0 +1,77 @@ +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; + +namespace NSubstitute.Analyzers.Shared.CodeFixProviders +{ + internal abstract class AbstractInternalSetupSpecificationCodeFixProvider : CodeFixProvider + where TCompilationUnitSyntax : SyntaxNode + { + public override ImmutableArray FixableDiagnosticIds { get; } = ImmutableArray.Create(DiagnosticIdentifiers.InternalSetupSpecification); + + protected abstract string ReplaceModifierCodeFixTitle { get; } + + public override async Task RegisterCodeFixesAsync(CodeFixContext context) + { + var diagnostic = + context.Diagnostics.FirstOrDefault(diag => diag.Id == DiagnosticIdentifiers.InternalSetupSpecification); + + if (diagnostic == null) + { + return; + } + + var root = await context.Document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); + var invocationExpression = root.FindNode(diagnostic.Location.SourceSpan, getInnermostNodeForTie: true); + var syntaxReference = await GetDeclaringSyntaxReference(context, invocationExpression); + + if (syntaxReference == null) + { + return; + } + + var syntaxNode = await syntaxReference.GetSyntaxAsync(); + + if (syntaxNode == null) + { + return; + } + + context.RegisterCodeFix(CodeAction.Create("Add protected modifier", token => AddModifierRefactoring(context.Document, syntaxNode, Accessibility.Protected)), diagnostic); + context.RegisterCodeFix(CodeAction.Create(ReplaceModifierCodeFixTitle, token => ReplaceModifierRefactoring(context.Document, syntaxNode, Accessibility.Internal, Accessibility.Public)), diagnostic); + + var compilationUnitSyntax = FindCompilationUnitSyntax(syntaxNode); + + if (compilationUnitSyntax == null) + { + return; + } + + RegisterAddInternalsVisibleToAttributeCodeFix(context, diagnostic, compilationUnitSyntax); + } + + protected abstract Task AddModifierRefactoring(Document document, SyntaxNode node, Accessibility accessibility); + + protected abstract Task ReplaceModifierRefactoring(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility); + + protected abstract void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, Diagnostic diagnostic, TCompilationUnitSyntax compilationUnitSyntax); + + private async Task GetDeclaringSyntaxReference(CodeFixContext context, SyntaxNode invocationExpression) + { + var semanticModel = await context.Document.GetSemanticModelAsync(context.CancellationToken); + var symbol = semanticModel.GetSymbolInfo(invocationExpression).Symbol; + + var firstOrDefault = symbol.DeclaringSyntaxReferences.FirstOrDefault(); + + return firstOrDefault; + } + + private TCompilationUnitSyntax FindCompilationUnitSyntax(SyntaxNode syntaxNode) + { + return syntaxNode.Parent.Ancestors().OfType().LastOrDefault(); + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs index 1a82a4fe..af11ce7b 100644 --- a/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.Shared/CodeFixProviders/AbstractSubstituteForInternalMemberCodeFixProvider.cs @@ -40,7 +40,6 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) } var syntaxNode = await syntaxReference.GetSyntaxAsync(); - var document = context.Document.Project.Solution.GetDocument(syntaxNode.SyntaxTree); var compilationUnitSyntax = FindCompilationUnitSyntax(syntaxNode); if (compilationUnitSyntax == null) @@ -48,21 +47,12 @@ public override async Task RegisterCodeFixesAsync(CodeFixContext context) return; } - var codeAction = CodeAction.Create("Add InternalsVisibleTo attribute", token => CreateChangedDocument(token, compilationUnitSyntax, document), nameof(AbstractSubstituteForInternalMemberCodeFixProvider)); - context.RegisterCodeFix(codeAction, diagnostic); + RegisterCodeFix(context, diagnostic, compilationUnitSyntax); } protected abstract AbstractSubstituteProxyAnalysis GetSubstituteProxyAnalysis(); - protected abstract TCompilationUnitSyntax AppendInternalsVisibleToAttribute(TCompilationUnitSyntax compilationUnitSyntax); - - private async Task CreateChangedDocument(CancellationToken cancellationToken, TCompilationUnitSyntax compilationUnitSyntax, Document document) - { - var updatedCompilationUnitSyntax = AppendInternalsVisibleToAttribute(compilationUnitSyntax); - var root = await document.GetSyntaxRootAsync(cancellationToken); - var replaceNode = root.ReplaceNode(compilationUnitSyntax, updatedCompilationUnitSyntax); - return document.WithSyntaxRoot(replaceNode); - } + protected abstract void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, TCompilationUnitSyntax compilationUnitSyntax); private async Task GetDeclaringSyntaxReference(CodeFixContext context, TInvocationExpressionSyntax invocationExpression) { diff --git a/src/NSubstitute.Analyzers.Shared/Extensions/DocumentExtensions.cs b/src/NSubstitute.Analyzers.Shared/Extensions/DocumentExtensions.cs new file mode 100644 index 00000000..f35c26da --- /dev/null +++ b/src/NSubstitute.Analyzers.Shared/Extensions/DocumentExtensions.cs @@ -0,0 +1,22 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; + +namespace NSubstitute.Analyzers.Shared.Extensions +{ + internal static class DocumentExtensions + { + public static async Task ReplaceNodeAsync( + this Document document, + SyntaxNode oldNode, + SyntaxNode newNode, + CancellationToken cancellationToken = default) + { + var root = await document.GetSyntaxRootAsync(cancellationToken); + + var newRoot = root.ReplaceNode(oldNode, newNode); + + return document.WithSyntaxRoot(newRoot); + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.Shared/NSubstitute.Analyzers.Shared.csproj b/src/NSubstitute.Analyzers.Shared/NSubstitute.Analyzers.Shared.csproj index 850e2dcf..8474dbb7 100644 --- a/src/NSubstitute.Analyzers.Shared/NSubstitute.Analyzers.Shared.csproj +++ b/src/NSubstitute.Analyzers.Shared/NSubstitute.Analyzers.Shared.csproj @@ -7,7 +7,7 @@ True false $(VersionSuffix) - 7.2 + latest diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs new file mode 100644 index 00000000..b581db71 --- /dev/null +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/InternalSetupSpecificationCodeFixProvider.cs @@ -0,0 +1,30 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using NSubstitute.Analyzers.Shared.CodeFixProviders; +using NSubstitute.Analyzers.VisualBasic.Refactorings; + +namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders +{ + [ExportCodeFixProvider(LanguageNames.VisualBasic)] + internal class InternalSetupSpecificationCodeFixProvider : AbstractInternalSetupSpecificationCodeFixProvider + { + protected override string ReplaceModifierCodeFixTitle { get; } = "Replace friend with public modifier"; + + protected override Task AddModifierRefactoring(Document document, SyntaxNode node, Accessibility accessibility) + { + return Refactorings.AddModifierRefactoring.RefactorAsync(document, node, accessibility); + } + + protected override Task ReplaceModifierRefactoring(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility) + { + return Refactorings.ReplaceModifierRefactoring.RefactorAsync(document, node, fromAccessibility, toAccessibility); + } + + protected override void RegisterAddInternalsVisibleToAttributeCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + { + AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, diagnostic, compilationUnitSyntax); + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs index 81b5fb1b..1c69c332 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs +++ b/src/NSubstitute.Analyzers.VisualBasic/CodeFixProviders/SubstituteForInternalMemberCodeFixProvider.cs @@ -5,6 +5,7 @@ using NSubstitute.Analyzers.Shared.CodeFixProviders; using NSubstitute.Analyzers.Shared.DiagnosticAnalyzers; using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; +using NSubstitute.Analyzers.VisualBasic.Refactorings; using static Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory; namespace NSubstitute.Analyzers.VisualBasic.CodeFixProviders @@ -17,23 +18,9 @@ protected override AbstractSubstituteProxyAnalysis(SimpleArgument( - LiteralExpression( - SyntaxKind.StringLiteralExpression, - Literal("DynamicProxyGenAssembly2"))))))))))); + AddInternalsVisibleToAttributeRefactoring.RegisterCodeFix(context, diagnostic, compilationUnitSyntax); } } } \ 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 9fa5e98b..17dfb096 100644 --- a/src/NSubstitute.Analyzers.VisualBasic/NSubstitute.Analyzers.VisualBasic.csproj +++ b/src/NSubstitute.Analyzers.VisualBasic/NSubstitute.Analyzers.VisualBasic.csproj @@ -7,6 +7,7 @@ true Properties $(VersionSuffix) + latest NSubstitute.Analyzers.VisualBasic diff --git a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs new file mode 100644 index 00000000..dc67f2a6 --- /dev/null +++ b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddInternalsVisibleToAttributeRefactoring.cs @@ -0,0 +1,46 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeActions; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using NSubstitute.Analyzers.Shared.Extensions; +using static Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory; + +namespace NSubstitute.Analyzers.VisualBasic.Refactorings +{ + internal static class AddInternalsVisibleToAttributeRefactoring + { + public static Task RefactorAsync(Document document, CompilationUnitSyntax compilationUnitSyntax, CancellationToken cancellationToken = default) + { + var addAttributeLists = compilationUnitSyntax.AddAttributes( + AttributesStatement(SingletonList( + AttributeList(SingletonSeparatedList(Attribute( + AttributeTarget(Token(SyntaxKind.AssemblyKeyword)), + QualifiedName( + QualifiedName( + QualifiedName( + IdentifierName("System"), + IdentifierName("Runtime")), + IdentifierName("CompilerServices")), + IdentifierName("InternalsVisibleTo")), + ArgumentList(SingletonSeparatedList(SimpleArgument( + LiteralExpression( + SyntaxKind.StringLiteralExpression, + Literal("DynamicProxyGenAssembly2"))))))))))); + + return document.ReplaceNodeAsync(compilationUnitSyntax, addAttributeLists, CancellationToken.None); + } + + public static void RegisterCodeFix(CodeFixContext context, Diagnostic diagnostic, CompilationUnitSyntax compilationUnitSyntax) + { + var codeAction = CodeAction.Create( + "Add InternalsVisibleTo attribute", + cancellationToken => RefactorAsync(context.Document, compilationUnitSyntax, cancellationToken), + diagnostic.Id); + + context.RegisterCodeFix(codeAction, context.Diagnostics); + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs new file mode 100644 index 00000000..b0a725f8 --- /dev/null +++ b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/AddModifierRefactoring.cs @@ -0,0 +1,49 @@ +using System; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using NSubstitute.Analyzers.Shared.Extensions; +using static Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory; + +namespace NSubstitute.Analyzers.VisualBasic.Refactorings +{ + internal static class AddModifierRefactoring + { + public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility accessibility) + { + SyntaxKind syntaxKind; + + switch (accessibility) + { + case Accessibility.Protected: + syntaxKind = SyntaxKind.ProtectedKeyword; + break; + default: + throw new NotSupportedException($"Adding {accessibility} modifier is not supported"); + } + + var newNode = Insert(node, syntaxKind); + + return document.ReplaceNodeAsync(node, newNode); + } + + private static SyntaxNode Insert(SyntaxNode node, SyntaxKind syntaxKind) + { + switch (node) + { + case MethodStatementSyntax methodDeclarationSyntax: + return methodDeclarationSyntax.WithModifiers(UpdateModifiers(methodDeclarationSyntax.Modifiers, syntaxKind)); + case PropertyStatementSyntax propertyDeclarationSyntax: + return propertyDeclarationSyntax.WithModifiers(UpdateModifiers(propertyDeclarationSyntax.Modifiers, syntaxKind)); + default: + throw new NotSupportedException($"Adding {syntaxKind} to {node.Kind()} is not supported"); + } + } + + private static SyntaxTokenList UpdateModifiers(SyntaxTokenList modifiers, SyntaxKind modifier) + { + return modifiers.Any(modifier) ? modifiers : modifiers.Insert(0, Token(modifier)); + } + } +} \ No newline at end of file diff --git a/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs new file mode 100644 index 00000000..4260c75e --- /dev/null +++ b/src/NSubstitute.Analyzers.VisualBasic/Refactorings/ReplaceModifierRefactoring.cs @@ -0,0 +1,61 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.VisualBasic; +using Microsoft.CodeAnalysis.VisualBasic.Syntax; +using NSubstitute.Analyzers.Shared.Extensions; +using static Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory; + +namespace NSubstitute.Analyzers.VisualBasic.Refactorings +{ + internal class ReplaceModifierRefactoring + { + public static Task RefactorAsync(Document document, SyntaxNode node, Accessibility fromAccessibility, Accessibility toAccessibility) + { + var fromSyntaxKind = InferSyntaxKind(fromAccessibility); + var toSyntaxKind = InferSyntaxKind(toAccessibility); + + var newNode = ReplaceModifier(node, fromSyntaxKind, toSyntaxKind); + + return document.ReplaceNodeAsync(node, newNode); + } + + private static SyntaxKind InferSyntaxKind(Accessibility fromAccessibility) + { + SyntaxKind syntaxKind; + switch (fromAccessibility) + { + case Accessibility.Internal: + syntaxKind = SyntaxKind.FriendKeyword; + break; + case Accessibility.Public: + syntaxKind = SyntaxKind.PublicKeyword; + break; + default: + throw new NotSupportedException($"Replacing {fromAccessibility} modifier is not supported"); + } + + return syntaxKind; + } + + private static SyntaxNode ReplaceModifier(SyntaxNode node, SyntaxKind fromSyntaxKind, SyntaxKind toSyntaxKind) + { + switch (node) + { + case MethodStatementSyntax methodDeclarationSyntax: + return methodDeclarationSyntax.WithModifiers(ReplaceModifier(methodDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); + case PropertyStatementSyntax propertyDeclarationSyntax: + return propertyDeclarationSyntax.WithModifiers(ReplaceModifier(propertyDeclarationSyntax.Modifiers, fromSyntaxKind, toSyntaxKind)); + default: + throw new NotSupportedException($"Replacing {fromSyntaxKind} in {node.Kind()} is not supported"); + } + } + + private static SyntaxTokenList ReplaceModifier(SyntaxTokenList modifiers, SyntaxKind fromModifier, SyntaxKind toModifier) + { + var modifier = modifiers.First(mod => mod.IsKind(fromModifier)); + return modifiers.Replace(modifier, Token(toModifier)); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs new file mode 100644 index 00000000..b042957a --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs @@ -0,0 +1,118 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.CSharp.CodeFixProviders; +using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; +using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.InternalSetupSpecificationCodeFixProviderTests +{ + public class InternalSetupSpecificationCodeFixActionsTests : CSharpCodeFixActionsVerifier, IInternalSetupSpecificationCodeFixActionsVerifier + { + [Fact] + public async Task CreateCodeActions_InProperOrder() + { + var source = @"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{ + public class Foo + { + internal virtual int Bar() + { + return 1; + } + } + + public class FooTests + { + public void Test() + { + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar().Returns(1); + } + } +}"; + await VerifyCodeActions(source, "Add protected modifier", "Replace internal with public modifier", "Add InternalsVisibleTo attribute"); + } + + [Fact] + public async Task DoesNotCreateCodeActions_WhenSymbol_DoesNotBelongToCompilation() + { + var source = @"using NSubstitute; +using ExternalNamespace; + +namespace MyNamespace +{ + public class FooTests + { + public void Test() + { + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar().Returns(1); + } + } +}"; + await VerifyCodeActions(source); + } + + protected override IEnumerable GetAdditionalMetadataReferences() + { + return new[] { GetInternalLibraryMetadataReference() }; + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberAnalyzer(); + } + + protected override CodeFixProvider GetCodeFixProvider() + { + return new InternalSetupSpecificationCodeFixProvider(); + } + + private static PortableExecutableReference GetInternalLibraryMetadataReference() + { + var syntaxTree = CSharpSyntaxTree.ParseText($@" +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""{TestProjectName}"")] +namespace ExternalNamespace +{{ + public class InternalFoo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} +}}"); + + var references = new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }; + var compilationOptions = new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary); + var compilation = CSharpCompilation.Create("Internal", new[] { syntaxTree }, references, compilationOptions); + + using (var ms = new MemoryStream()) + { + var result = compilation.Emit(ms); + + if (result.Success == false) + { + var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); + throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); + } + + ms.Seek(0, SeekOrigin.Begin); + return MetadataReference.CreateFromStream(ms); + } + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixProviderVerifier.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixProviderVerifier.cs new file mode 100644 index 00000000..fd655969 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixProviderVerifier.cs @@ -0,0 +1,54 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.CSharp.CodeFixProviders; +using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; +using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.InternalSetupSpecificationCodeFixProviderTests +{ + public abstract class InternalSetupSpecificationCodeFixProviderVerifier : CSharpSuppressDiagnosticSettingsVerifier, IInternalSetupSpecificationCodeFixProviderVerifier + { + [CombinatoryTheory] + [InlineData] + public abstract Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData(".Bar")] + [InlineData(".FooBar()")] + [InlineData("[0]")] + public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call); + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberAnalyzer(); + } + + protected override CodeFixProvider GetCodeFixProvider() + { + return new InternalSetupSpecificationCodeFixProvider(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsExtensionMethodTests.cs new file mode 100644 index 00000000..4b8bb856 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsExtensionMethodTests.cs @@ -0,0 +1,389 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; +using NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonSubstitutableMemberReceivedAnalyzerTests; +using NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonSubstitutableMemberWhenAnalyzerTests; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; + +namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("Received")] + public class ReceivedAsExtensionMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}()[0]; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}()[0]; + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}().Bar; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}().Bar; + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}().Bar(); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}().Bar(); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}()[0]; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}()[0]; + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}().Bar; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}().Bar; + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}().Bar(); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}().Bar(); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}(){call}; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""DynamicProxyGenAssembly2"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.{method}(){call}; + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 2); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberReceivedAnalyzer(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..88f12926 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs @@ -0,0 +1,387 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; + +namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("SubstituteExtensions.Received")] + public class ReceivedAsOrdinaryMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute)[0]; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute)[0]; + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute).Bar; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute).Bar; + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute).Bar(); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute).Bar(); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute)[0]; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute)[0]; + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute).Bar; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute).Bar; + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute).Bar(); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute).Bar(); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute){call}; + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""DynamicProxyGenAssembly2"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute){call}; + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 2); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberReceivedAnalyzer(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs new file mode 100644 index 00000000..977a7bb5 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs @@ -0,0 +1,381 @@ +using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("Returns")] + public class ReturnsAsExtensionMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute[0].{method}(1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute[0].{method}(1); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar.{method}(1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar.{method}(1); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar().{method}(1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar().{method}(1); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute[0].{method}(1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute[0].{method}(1); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar.{method}(1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar.{method}(1); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar().{method}(1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute.Bar().{method}(1); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute{call}.{method}(1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""DynamicProxyGenAssembly2"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = substitute{call}.{method}(1); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 2); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..81343375 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs @@ -0,0 +1,381 @@ +using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("SubstituteExtensions.Returns")] + public class ReturnsAsOrdinaryMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute[0], 1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute[0], 1); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute.Bar, 1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute.Bar, 1); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute.Bar(), 1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute.Bar(), 1); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute[0], 1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute[0], 1); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute.Bar, 1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute.Bar, 1); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute.Bar(), 1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute.Bar(), 1); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute{call}, 1); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""DynamicProxyGenAssembly2"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + var x = {method}(substitute{call}, 1); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 2); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsExtensionMethodTests.cs new file mode 100644 index 00000000..b68863d1 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsExtensionMethodTests.cs @@ -0,0 +1,388 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; +using NSubstitute.Analyzers.Tests.CSharp.DiagnosticAnalyzerTests.NonSubstitutableMemberWhenAnalyzerTests; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; + +namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("When")] + public class WhenAsExtensionMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo[0];}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo[0];}}); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo.Bar;}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo.Bar;}}); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => callInfo.Bar()); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => callInfo.Bar()); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo[0];}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo[0];}}); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo.Bar;}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo.Bar;}}); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => callInfo.Bar()); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => callInfo.Bar()); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo{call};}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""DynamicProxyGenAssembly2"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + substitute.{method}(callInfo => {{var x = callInfo{call};}}); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 2); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberWhenAnalyzer(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..37552f45 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.CSharp/CodeFixProviderTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsOrdinaryMethodTests.cs @@ -0,0 +1,387 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.CSharp.DiagnosticAnalyzers; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; + +namespace NSubstitute.Analyzers.Tests.CSharp.CodeFixProviderTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("SubstituteExtensions.When")] + public class WhenAsOrdinaryMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo[0];}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo[0];}}); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo.Bar;}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo.Bar;}}); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => callInfo.Bar()); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + public virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => callInfo.Bar()); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo[0];}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo[0];}}); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo.Bar;}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo.Bar;}}); + }} + }} +}}"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => callInfo.Bar()); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; + +namespace MyNamespace +{{ + public class Foo + {{ + protected internal virtual int Bar() + {{ + return 1; + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => callInfo.Bar()); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo{call};}}); + }} + }} +}}"; + + var newSource = $@"using NSubstitute; +using System.Runtime.CompilerServices; +[assembly: InternalsVisibleTo(""OtherAssembly"")] +[assembly: System.Runtime.CompilerServices.InternalsVisibleTo(""DynamicProxyGenAssembly2"")] + +namespace MyNamespace +{{ + public class Foo + {{ + internal virtual int Bar {{ get; }} + + internal virtual int FooBar() + {{ + return 1; + }} + + internal virtual int this[int x] + {{ + get {{ return 1; }} + }} + }} + + public class FooTests + {{ + public void Test() + {{ + var substitute = NSubstitute.Substitute.For(); + {method}(substitute, callInfo => {{var x = callInfo{call};}}); + }} + }} +}}"; + await VerifyFix(oldSource, newSource, 2); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberWhenAnalyzer(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/IInternalSetupSpecificationCodeFixActionsVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/IInternalSetupSpecificationCodeFixActionsVerifier.cs new file mode 100644 index 00000000..1d09aac5 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/IInternalSetupSpecificationCodeFixActionsVerifier.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; + +namespace NSubstitute.Analyzers.Tests.Shared.CodeFixProviders +{ + public interface IInternalSetupSpecificationCodeFixActionsVerifier + { + Task CreateCodeActions_InProperOrder(); + + Task DoesNotCreateCodeActions_WhenSymbol_DoesNotBelongToCompilation(); + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/IInternalSetupSpecificationCodeFixProviderVerifier.cs b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/IInternalSetupSpecificationCodeFixProviderVerifier.cs new file mode 100644 index 00000000..ce9aa1cf --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.Shared/CodeFixProviders/IInternalSetupSpecificationCodeFixProviderVerifier.cs @@ -0,0 +1,21 @@ +using System.Threading.Tasks; + +namespace NSubstitute.Analyzers.Tests.Shared.CodeFixProviders +{ + public interface IInternalSetupSpecificationCodeFixProviderVerifier + { + Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method); + + Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method); + + Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method); + + Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method); + + Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method); + + Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method); + + Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call); + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs new file mode 100644 index 00000000..6af9be49 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixActionsTests.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.VisualBasic; +using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; +using NSubstitute.Analyzers.VisualBasic.CodeFixProviders; +using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.InternalSetupSpecificationCodeFixProviderTests +{ + public class InternalSetupSpecificationCodeFixActionsTests : VisualBasicCodeFixActionsVerifier, IInternalSetupSpecificationCodeFixActionsVerifier + { + [Fact] + public async Task CreateCodeActions_InProperOrder() + { + var source = @"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.Bar().Returns(1) + End Sub + End Class +End Namespace +"; + await VerifyCodeActions(source, "Add protected modifier", "Replace friend with public modifier", "Add InternalsVisibleTo attribute"); + } + + [Fact] + public async Task DoesNotCreateCodeActions_WhenSymbol_DoesNotBelongToCompilation() + { + var source = @"Imports NSubstitute +Imports ExternalNamespace + +Namespace MyNamespace + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of InternalFoo)() + Dim x = substitute.Bar().Returns(1) + End Sub + End Class +End Namespace"; + + await VerifyCodeActions(source); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberAnalyzer(); + } + + protected override CodeFixProvider GetCodeFixProvider() + { + return new InternalSetupSpecificationCodeFixProvider(); + } + + protected override IEnumerable GetAdditionalMetadataReferences() + { + return new[] { GetInternalLibraryMetadataReference() }; + } + + private static PortableExecutableReference GetInternalLibraryMetadataReference() + { + var syntaxTree = VisualBasicSyntaxTree.ParseText($@"Imports System.Runtime.CompilerServices + + +Namespace ExternalNamespace + Public Class InternalFoo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class +End Namespace +"); + + var references = new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) }; + var compilationOptions = new VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary); + var compilation = VisualBasicCompilation.Create("Internal", new[] { syntaxTree }, references, compilationOptions); + + using (var ms = new MemoryStream()) + { + var result = compilation.Emit(ms); + + if (result.Success == false) + { + var errors = result.Diagnostics.Where(diag => diag.IsWarningAsError || diag.Severity == DiagnosticSeverity.Error); + throw new InvalidOperationException($"Internal library compilation failed: {string.Join(",", errors)}"); + } + + ms.Seek(0, SeekOrigin.Begin); + return MetadataReference.CreateFromStream(ms); + } + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixProviderVerifier.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixProviderVerifier.cs new file mode 100644 index 00000000..929b792e --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/InternalSetupSpecificationCodeFixProviderVerifier.cs @@ -0,0 +1,54 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.Tests.Shared.CodeFixProviders; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; +using NSubstitute.Analyzers.VisualBasic.CodeFixProviders; +using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; +using Xunit; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.InternalSetupSpecificationCodeFixProviderTests +{ + public abstract class InternalSetupSpecificationCodeFixProviderVerifier : VisualBasicCodeFixVerifier, IInternalSetupSpecificationCodeFixProviderVerifier + { + [CombinatoryTheory] + [InlineData] + public abstract Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData] + public abstract Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method); + + [CombinatoryTheory] + [InlineData(".Bar")] + [InlineData(".FooBar()")] + [InlineData("(0)")] + public abstract Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call); + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberAnalyzer(); + } + + protected override CodeFixProvider GetCodeFixProvider() + { + return new InternalSetupSpecificationCodeFixProvider(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsExtensionMethodTests.cs new file mode 100644 index 00000000..c4a66cd7 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsExtensionMethodTests.cs @@ -0,0 +1,345 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; +using NSubstitute.Analyzers.Tests.VisualBasic.DiagnosticAnalyzersTests.NonSubstitutableMemberReceivedAnalyzerTests; +using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("Received")] + public class ReceivedAsExtensionMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}()(1) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Public Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}()(1) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}().Bar + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}().Bar + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}().Bar() + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}().Bar() + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}()(0) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}()(0) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}().Bar + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}().Bar + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}().Bar() + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}().Bar() + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}(){call} + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.{method}(){call} + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 2); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberReceivedAnalyzer(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..0f9cff22 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReceivedAsOrdinaryMethodTests.cs @@ -0,0 +1,344 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; +using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("SubstituteExtensions.Received")] + public class ReceivedAsOrdinaryMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute)(1) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Public Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute)(1) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute).Bar + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute).Bar + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute).Bar() + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute).Bar() + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute)(1) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute)(1) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute).Bar + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute).Bar + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute).Bar() + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute).Bar() + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute){call} + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute){call} + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 2); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberReceivedAnalyzer(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs new file mode 100644 index 00000000..42ccf3ad --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsExtensionMethodTests.cs @@ -0,0 +1,337 @@ +using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("Returns")] + public class ReturnsAsExtensionMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute(0).{method}(1) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Public Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute(0).{method}(1) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.Bar.{method}(1) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.Bar.{method}(1) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.Bar().{method}(1) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.Bar().{method}(1) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute(0).{method}(1) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute(0).{method}(1) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.Bar.{method}(1) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.Bar.{method}(1) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.Bar().{method}(1) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute.Bar().{method}(1) + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute{call}.{method}(1) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = substitute{call}.{method}(1) + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 2); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..b30c1496 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/ReturnsAsOrdinaryMethodTests.cs @@ -0,0 +1,337 @@ +using System.Threading.Tasks; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("SubstituteExtensions.Returns")] + public class ReturnsAsOrdinaryMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute(0), 1) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Public Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute(0), 1) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute.Bar, 1) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute.Bar, 1) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute.Bar(), 1) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute.Bar(), 1) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute(0), 1) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute(0), 1) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute.Bar, 1) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute.Bar, 1) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute.Bar(), 1) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute.Bar(), 1) + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute{call}, 1) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + Dim x = {method}(substitute{call}, 1) + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 2); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsExtensionMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsExtensionMethodTests.cs new file mode 100644 index 00000000..3012f9b7 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsExtensionMethodTests.cs @@ -0,0 +1,373 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; +using NSubstitute.Analyzers.VisualBasic.CodeFixProviders; +using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("When")] + public class WhenAsExtensionMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb(0) + End Sub) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Public Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb(0) + End Sub) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb.Bar + End Sub) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb.Bar + End Sub) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb.Bar() + End Sub) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb.Bar() + End Sub) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb(0) + End Sub) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb(0) + End Sub) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb.Bar + End Sub) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb.Bar + End Sub) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb.Bar() + End Sub) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb.Bar() + End Sub) + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb{call} + End Sub) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + substitute.{method}(Sub(sb As Foo) + Dim x = sb{call} + End Sub) + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 2); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberWhenAnalyzer(); + } + } +} \ No newline at end of file diff --git a/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsOrdinaryMethodTests.cs b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsOrdinaryMethodTests.cs new file mode 100644 index 00000000..fa01e0e8 --- /dev/null +++ b/tests/NSubstitute.Analyzers.Tests.VisualBasic/CodeFixProvidersTests/InternalSetupSpecificationCodeFixProviderTests/WhenAsOrdinaryMethodTests.cs @@ -0,0 +1,372 @@ +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using NSubstitute.Analyzers.Tests.Shared.Extensibility; +using NSubstitute.Analyzers.VisualBasic.DiagnosticAnalyzers; + +namespace NSubstitute.Analyzers.Tests.VisualBasic.CodeFixProvidersTests.InternalSetupSpecificationCodeFixProviderTests +{ + [CombinatoryData("SubstituteExtensions.When")] + public class WhenAsOrdinaryMethodTests : InternalSetupSpecificationCodeFixProviderVerifier + { + public override async Task ChangesInternalToPublic_ForIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb(0) + End Sub) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Public Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb(0) + End Sub) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb.Bar + End Sub) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb.Bar + End Sub) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task ChangesInternalToPublic_ForMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb.Bar() + End Sub) + End Sub + End Class +End Namespace"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Public Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb.Bar() + End Sub) + End Sub + End Class +End Namespace"; + + await VerifyFix(oldSource, newSource, 1); + } + + public override async Task AppendsProtectedInternal_ToIndexer_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb(0) + End Sub) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb(0) + End Sub) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToProperty_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb.Bar + End Sub) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable ReadOnly Property Bar As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb.Bar + End Sub) + End Sub + End Class +End Namespace +"; + + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsProtectedInternal_ToMethod_WhenUsedWithInternalMember(string method) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb.Bar() + End Sub) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + +Namespace MyNamespace + Public Class Foo + Protected Friend Overridable Function Bar() As Integer + Return 1 + End Function + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb.Bar() + End Sub) + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 0); + } + + public override async Task AppendsInternalsVisibleTo_ToTopLevelCompilationUnit_WhenUsedWithInternalMember(string method, string call) + { + var oldSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb{call} + End Sub) + End Sub + End Class +End Namespace +"; + + var newSource = $@"Imports NSubstitute +Imports System.Runtime.CompilerServices + + + +Namespace MyNamespace + Public Class Foo + Friend Overridable ReadOnly Property Bar As Integer + + Friend Overridable Function FooBar() As Integer + Return 1 + End Function + + Default Friend Overridable ReadOnly Property Item(ByVal x As Integer) As Integer + Get + Return 1 + End Get + End Property + End Class + + Public Class FooTests + Public Sub Test() + Dim substitute = NSubstitute.Substitute.[For](Of Foo)() + {method}(substitute, Sub(sb As Foo) + Dim x = sb{call} + End Sub) + End Sub + End Class +End Namespace +"; + await VerifyFix(oldSource, newSource, 2); + } + + protected override DiagnosticAnalyzer GetDiagnosticAnalyzer() + { + return new NonSubstitutableMemberWhenAnalyzer(); + } + } +} \ No newline at end of file