File: Microsoft.CodeQuality.Analyzers\ApiDesignGuidelines\DoNotPassTypesByReferenceTests.cs
Web Access
Project: ..\..\..\src\Microsoft.CodeAnalysis.NetAnalyzers\tests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests\Microsoft.CodeAnalysis.NetAnalyzers.UnitTests.csproj (Microsoft.CodeAnalysis.NetAnalyzers.UnitTests)
// Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the MIT license.  See License.txt in the project root for license information.
 
using System.Threading.Tasks;
using Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.DoNotPassTypesByReference,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.DoNotPassTypesByReference,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
 
namespace Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.UnitTests
{
    public class DoNotPassTypesByReferenceTests
    {
        [Fact]
        public async Task CA1045_RefParameters_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class Class1
{
    public void Method1(ref string s, ref object o)
    {
    }
}",
                VerifyCS.Diagnostic().WithSpan(4, 36, 4, 37).WithArguments("s"),
                VerifyCS.Diagnostic().WithSpan(4, 50, 4, 51).WithArguments("o"));
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Class Class1
    Public Sub Method1(ByRef s As String, ByRef o As Object)
    End Sub
End Class",
                VerifyVB.Diagnostic().WithSpan(3, 30, 3, 31).WithArguments("s"),
                VerifyVB.Diagnostic().WithSpan(3, 49, 3, 50).WithArguments("o"));
        }
 
        [Fact]
        public async Task CA1045_MethodIsNotPublic_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class Class1
{
    private void Method1(ref string s)
    {
    }
}");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Class Class1
    Private Sub Method1(ByRef s As String)
    End Sub
End Class");
        }
 
        [Fact]
        public async Task CA1045_MethodIsOverride_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class BaseClass
{
    public virtual void Method1(ref string [|s|]) // issue here...
    {
    }
}
 
public class Class1 : BaseClass
{
    public override void Method1(ref string s) // ... but not here
    {
    }
}");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Class BaseClass
    Public Overridable Sub Method1(ByRef [|s|] As String) ' issue here...
    End Sub
End Class
 
Public Class Class1
    Inherits BaseClass
 
    Public Overrides Sub Method1(ByRef s As String) ' ... but not here
    End Sub
End Class
");
        }
 
        [Fact]
        public async Task CA1045_MethodIsInterfaceImplementation_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public interface Interface1
{
    void Method1(ref string [|s|]); // issue here...
}
 
public class Class1 : Interface1
{
    public void Method1(ref string s) // ... but not here
    {
    }
}");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Interface Interface1
    Sub Method1(ByRef [|s|] As String) ' issue here...
End Interface
 
Public Class Class1
    Implements Interface1
 
    Public Sub Method1(ByRef s As String) Implements Interface1.Method1 ' ... but not here
    End Sub
End Class");
        }
 
        [Fact]
        public async Task CA1045_OutParameter_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class Class1
{
    private void Method1(out string s)
    {
        s = string.Empty;
    }
}");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System.Runtime.InteropServices
 
Public Class Class1
    Public Sub Method1(s As String, <Out> ByRef c1 As Class1, ByRef [|c2|] As Class1)
        c1 = Nothing
    End Sub
End Class");
        }
 
        [Fact]
        public async Task CA1045_PInvokeMethod_DiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Runtime.InteropServices;
 
public class Class1
{
    [DllImport(""Advapi32.dll"", CharSet=CharSet.Auto)]
    public static extern Boolean FileEncryptionStatus(String filename, ref UInt32 [|status|]);
}");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System.Runtime.InteropServices
 
Public Class Class1
    <DllImport(""Advapi32.dll"", CharSet:=CharSet.Auto)>
    Public Shared Function FileEncryptionStatus(ByVal filename As String, ByRef [|status|] As UInteger) As Boolean
    End Function
End Class");
        }
 
        [Fact]
        public async Task CA1045_InParameter_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class Class1
{
    private void Method1(in Class1 c)
    {
    }
}");
        }
 
        [Theory]
        // General analyzer option
        [InlineData("public", "dotnet_code_quality.api_surface = public")]
        [InlineData("public", "dotnet_code_quality.api_surface = private, internal, public")]
        [InlineData("public", "dotnet_code_quality.api_surface = all")]
        [InlineData("protected", "dotnet_code_quality.api_surface = public")]
        [InlineData("protected", "dotnet_code_quality.api_surface = private, internal, public")]
        [InlineData("protected", "dotnet_code_quality.api_surface = all")]
        [InlineData("internal", "dotnet_code_quality.api_surface = internal")]
        [InlineData("internal", "dotnet_code_quality.api_surface = private, internal")]
        [InlineData("internal", "dotnet_code_quality.api_surface = all")]
        [InlineData("private", "dotnet_code_quality.api_surface = private")]
        [InlineData("private", "dotnet_code_quality.api_surface = private, public")]
        [InlineData("private", "dotnet_code_quality.api_surface = all")]
        // Specific analyzer option
        [InlineData("internal", "dotnet_code_quality.CA1045.api_surface = all")]
        [InlineData("internal", "dotnet_code_quality.Design.api_surface = all")]
        // General + Specific analyzer option
        [InlineData("internal", @"dotnet_code_quality.api_surface = private
                                  dotnet_code_quality.CA1045.api_surface = all")]
        // Case-insensitive analyzer option
        [InlineData("internal", "DOTNET_code_quality.CA1045.API_SURFACE = ALL")]
        // Invalid analyzer option ignored
        [InlineData("internal", @"dotnet_code_quality.api_surface = all
                                  dotnet_code_quality.CA1045.api_surface_2 = private")]
        public async Task CSharp_ApiSurfaceOptionAsync(string accessibility, string editorConfigText)
        {
            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        $@"
public class C
{{
    {accessibility} void M(ref string [|s|]) {{ }}
}}"
                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
 
[*]
{editorConfigText}
"), },
                },
            }.RunAsync();
        }
 
        [Theory]
        // General analyzer option
        [InlineData("Public", "dotnet_code_quality.api_surface = Public")]
        [InlineData("Public", "dotnet_code_quality.api_surface = Private, Friend, Public")]
        [InlineData("Public", "dotnet_code_quality.api_surface = All")]
        [InlineData("Protected", "dotnet_code_quality.api_surface = Public")]
        [InlineData("Protected", "dotnet_code_quality.api_surface = Private, Friend, Public")]
        [InlineData("Protected", "dotnet_code_quality.api_surface = All")]
        [InlineData("Friend", "dotnet_code_quality.api_surface = Friend")]
        [InlineData("Friend", "dotnet_code_quality.api_surface = Private, Friend")]
        [InlineData("Friend", "dotnet_code_quality.api_surface = All")]
        [InlineData("Private", "dotnet_code_quality.api_surface = Private")]
        [InlineData("Private", "dotnet_code_quality.api_surface = Private, Public")]
        [InlineData("Private", "dotnet_code_quality.api_surface = All")]
        // Specific analyzer option
        [InlineData("Friend", "dotnet_code_quality.CA1045.api_surface = All")]
        [InlineData("Friend", "dotnet_code_quality.Design.api_surface = All")]
        // General + Specific analyzer option
        [InlineData("Friend", @"dotnet_code_quality.api_surface = Private
                                dotnet_code_quality.CA1045.api_surface = All")]
        // Case-insensitive analyzer option
        [InlineData("Friend", "DOTNET_code_quality.CA1045.API_SURFACE = ALL")]
        // Invalid analyzer option ignored
        [InlineData("Friend", @"dotnet_code_quality.api_surface = All
                                dotnet_code_quality.CA1045.api_surface_2 = Private")]
        public async Task VisualBasic_ApiSurfaceOptionAsync(string accessibility, string editorConfigText)
        {
            await new VerifyVB.Test
            {
                TestState =
                {
                    Sources =
                    {
                        $@"
Public Class C
    {accessibility} Sub M(ByRef [|s|] As String)
    End Sub
End Class",
                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
 
[*]
{editorConfigText}
"), },
                },
            }.RunAsync();
        }
    }
}