File: Microsoft.CodeQuality.Analyzers\ApiDesignGuidelines\UsePropertiesWhereAppropriateTests.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 Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
using Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.UsePropertiesWhereAppropriateAnalyzer,
    Microsoft.CodeQuality.CSharp.Analyzers.ApiDesignGuidelines.CSharpUsePropertiesWhereAppropriateFixer>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.UsePropertiesWhereAppropriateAnalyzer,
    Microsoft.CodeQuality.VisualBasic.Analyzers.ApiDesignGuidelines.BasicUsePropertiesWhereAppropriateFixer>;
 
namespace Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.UnitTests
{
    public class UsePropertiesWhereAppropriateTests
    {
        [Fact]
        public async Task CSharp_CA1024NoDiagnosticCasesAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Collections;
 
public class GenericType<T>
{
}
 
public class Base
{
    public virtual int GetSomething()
    {
        return 0;
    }
 
    public virtual int GetOverloadedMethod()
    {
        return 1;
    }
 
    public virtual int GetOverloadedMethod(int i)
    {
        return i;
    }
}
 
public class Class1 : Base
{
    private string fileName = """";
 
    // 1) Returns void
    public void GetWronglyNamedMethod()
    {
    }
 
    // 2) Not a method
    public string LogFile
    {
        get { return fileName; }
    }
 
    // 3) Returns an array type
    public int[] GetValues()
    {
        return null;
    }
 
    // 4) Has parameters
    public int[] GetMethodWithParameters(int p)
    {
        return new int[] { p };
    }
 
    // 5a) Name doesn't start with a 'Get'
    public int SomeMethod()
    {
        return 0;
    }
 
    // 5b) First compound word is not 'Get'
    public int GetterMethod()
    {
        return 0;
    }
 
    // 6) Generic method
    public object GetGenericMethod<T>()
    {
        return new GenericType<T>();
    }
 
    // 7) Override
    public override int GetSomething()
    {
        return 1;
    }
 
    // 8) Method with overloads
    public override int GetOverloadedMethod()
    {
        return 1;
    }
 
    public override int GetOverloadedMethod(int i)
    {
        return i;
    }
 
    // 9) Methods with special name
    public override int GetHashCode()
    {
        return 0;
    }
 
    public IEnumerator GetEnumerator()
    {
        return null;
    }
 
    public ref string GetPinnableReference() // If the method isn't ref-returning, there will be a diagnostic.
    {
        return ref fileName;
    }
 
    // 10) Method with invocation expressions
    public int GetSomethingWithInvocation()
    {
        Console.WriteLine(this);
        return 0;
    }
 
    // 11) Method named 'Get'
    public string Get()
    {
        return fileName;
    }
 
    // 12) Private method
    private string GetSomethingPrivate()
    {
        return fileName;
    }
 
    // 13) Internal method
    internal string GetSomethingInternal()
    {
        return fileName;
    }
}
 
public class Class2
{
    private string fileName = """";
 
    public ref readonly string GetPinnableReference() // If the method isn't ref-returning, there will be a diagnostic.
    {
        return ref fileName;
    }
}
");
        }
 
        [Fact]
        public async Task CSharp_CA1024DiagnosticCasesAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class Class
{
    private string fileName = ""data.txt"";
 
    public string GetFileName()
    {
        return fileName;
    }
 
    public string Get_FileName2()
    {
        return fileName;
    }
 
    public string Get123()
    {
        return fileName;
    }
 
    protected string GetFileNameProtected()
    {
        return fileName;
    }
 
    public int GetPinnableReference() // Not a ref-return method.
    {
        return 0;
    }
}
",
            GetCA1024CSharpResultAt(6, 19, "GetFileName"),
            GetCA1024CSharpResultAt(11, 19, "Get_FileName2"),
            GetCA1024CSharpResultAt(16, 19, "Get123"),
            GetCA1024CSharpResultAt(21, 22, "GetFileNameProtected"),
            GetCA1024CSharpResultAt(26, 16, "GetPinnableReference"));
        }
 
        [Fact, WorkItem(1432, "https://github.com/dotnet/roslyn-analyzers/issues/1432")]
        public async Task CSharp_CA1024NoDiagnosticCases_InternalAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class Class
{
    private string fileName = ""data.txt"";
 
    internal string GetFileName()
    {
        return fileName;
    }
 
    private string Get_FileName2()
    {
        return fileName;
    }
 
    private class InnerClass
    {
        private string fileName = ""data.txt"";
 
        public string Get123()
        {
            return fileName;
        }
    }
}
");
        }
 
        [Fact]
        public async Task VisualBasic_CA1024NoDiagnosticCasesAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System.Collections
 
Public Class Base
    Public Overridable Function GetSomething() As Integer
        Return 0
    End Function
End Class
 
Public Class Class1
    Inherits Base
    Private fileName As String
 
    ' 1) Returns void
    Public Sub GetWronglyNamedMethod()
    End Sub
 
    ' 2) Not a method
    Public ReadOnly Property LogFile() As String
        Get
            Return fileName
        End Get
    End Property
 
    ' 3) Returns an array type
    Public Function GetValues() As Integer()
        Return Nothing
    End Function
 
    ' 4) Has parameters
    Public Function GetMethodWithParameters(p As Integer) As Integer()
        Return New Integer() {p}
    End Function
 
    ' 5a) Name doesn't start with a 'Get'
    Public Function SomeMethod() As Integer
        Return 0
    End Function
 
    ' 5b) First compound word is not 'Get'
    Public Function GetterMethod() As Integer
        Return 0
    End Function
 
    ' 6) Generic method
    Public Function GetGenericMethod(Of T)() As Object
        Return New GenericType(Of T)()
    End Function
 
    ' 7) Override
    Public Overrides Function GetSomething() As Integer
        Return 1
    End Function
 
    ' 8) Method with overloads
    Public Function GetOverloadedMethod() As Integer
        Return 1
    End Function
 
    Public Function GetOverloadedMethod(i As Integer) As Integer
        Return i
    End Function
 
    ' 9) Methods with special name
    Public Overloads Function GetHashCode() As Integer
        Return 0
    End Function
 
    Public Function GetEnumerator() As IEnumerator
        Return Nothing
    End Function
 
    ' 10) Method with invocation expressions
    Public Function GetSomethingWithInvocation() As Integer
        System.Console.WriteLine(Me)
        Return 0
    End Function
 
    ' 11) Method named 'Get'
    Public Function [Get]() As String
        Return fileName
    End Function
 
    ' 12) Private method
    Private Function GetSomethingPrivate() As String
        Return fileName
    End Function
 
    ' 13) Friend method
    Friend Function GetSomethingInternal() As String
        Return fileName
    End Function
End Class
 
Public Class GenericType(Of T)
End Class
");
        }
 
        [Fact]
        public async Task CSharp_CA1024NoDiagnosticOnUnboundMethodCallerAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
 
public class class1
{
    public int GetSomethingWithUnboundInvocation()
    {
        Console.WriteLine(this);
        return 0;
    }
}
");
        }
 
        [Fact]
        public async Task VisualBasic_CA1024NoDiagnosticOnUnboundMethodCallerAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System
 
Public Class class1
    Public Function GetSomethingWithUnboundInvocation() As Integer
        Console.WriteLine(Me)
        Return 0
    End Function
End Class
");
        }
 
        [Fact]
        public async Task VisualBasic_CA1024DiagnosticCasesAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Class Class1
    Private fileName As String
 
    Public Function GetFileName() As String
        Return filename
    End Function
 
    Public Function Get_FileName2() As String
        Return filename
    End Function
 
    Public Function Get123() As String
        Return filename
    End Function
 
    Protected Function GetFileNameProtected() As String
        Return filename
    End Function
End Class
",
            GetCA1024BasicResultAt(5, 21, "GetFileName"),
            GetCA1024BasicResultAt(9, 21, "Get_FileName2"),
            GetCA1024BasicResultAt(13, 21, "Get123"),
            GetCA1024BasicResultAt(17, 24, "GetFileNameProtected"));
        }
 
        [Fact, WorkItem(1432, "https://github.com/dotnet/roslyn-analyzers/issues/1432")]
        public async Task VisualBasic_CA1024NoDiagnosticCases_InternalAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Class Class1
    Private fileName As String
 
    Friend Function GetFileName() As String
        Return filename
    End Function
 
    Private Function Get_FileName2() As String
        Return filename
    End Function
 
    Private Class InnerClass
        Private fileName As String
 
        Public Function Get123() As String
            Return filename
        End Function
    End Class
End Class
");
        }
 
        [Fact, WorkItem(1551, "https://github.com/dotnet/roslyn-analyzers/issues/1551")]
        public async Task CA1024_ExplicitInterfaceImplementation_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public interface ISomething
{
    object GetContent();
}
 
public class Something : ISomething
{
    object ISomething.GetContent()
    {
        return null;
    }
}
");
        }
 
        [Fact, WorkItem(1551, "https://github.com/dotnet/roslyn-analyzers/issues/1551")]
        public async Task CA1024_ImplicitInterfaceImplementation_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public interface ISomething
{
    object GetContent();
}
 
public class Something : ISomething
{
    public object GetContent()
    {
        return null;
    }
}
");
        }
 
        [Fact, WorkItem(3877, "https://github.com/dotnet/roslyn-analyzers/issues/3877")]
        public async Task CA1024_ReturnsTask_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System.Threading.Tasks;
 
public class Something
{
    public Task GetTask() => default(Task);
    public Task<int> GetGenericTask() => default(Task<int>);
 
    public ValueTask GetValueTask() => default(ValueTask);
    public ValueTask<int> GetGenericValueTask() => default(ValueTask<int>);
}
");
 
            await VerifyVB.VerifyAnalyzerAsync(@"
Imports System.Threading.Tasks
 
Public Class Something
    Public Function GetTask() As Task
        Return Nothing
    End Function
 
    Public Function GetGenericTask() As Task(Of Integer)
        Return Nothing
    End Function
 
    Public Function GetValueTask() As ValueTask
        Return Nothing
    End Function
 
    Public Function GetGenericValueTask() As ValueTask(Of Integer)
        Return Nothing
    End Function
End Class
");
        }
 
        [Fact, WorkItem(4623, "https://github.com/dotnet/roslyn-analyzers/issues/4623")]
        public async Task AwaiterPattern_INotifyCompletion_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Runtime.CompilerServices;
 
public class DummyAwaiter : INotifyCompletion
{
    public object GetResult() => null;
 
    public bool IsCompleted => false;
 
    public void OnCompleted(Action continuation) => throw null;
}");
        }
 
        [Fact, WorkItem(4623, "https://github.com/dotnet/roslyn-analyzers/issues/4623")]
        public async Task AwaiterPattern_ICriticalNotifyCompletion_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Runtime.CompilerServices;
 
public class DummyAwaiter : ICriticalNotifyCompletion
{
    public object GetResult() => null;
 
    public bool IsCompleted => false;
 
    public void OnCompleted(Action continuation) => throw null;
    public void UnsafeOnCompleted(Action continuation) => throw null;
}");
        }
 
        [Fact, WorkItem(4623, "https://github.com/dotnet/roslyn-analyzers/issues/4623")]
        public async Task AwaitablePattern_NoDiagnosticAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Runtime.CompilerServices;
 
public class DummyAwaitable
{
    public DummyAwaiter GetAwaiter() => new DummyAwaiter();
}
 
public class DummyAwaiter : INotifyCompletion
{
    public void GetResult()
    {
    }
 
    public bool IsCompleted => false;
 
    public void OnCompleted(Action continuation) => throw null;
}");
        }
 
        [Fact, WorkItem(6031, "https://github.com/dotnet/roslyn-analyzers/issues/6031")]
        public async Task DllImportAttribute_NoDiagnostic()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
using System;
using System.Runtime.InteropServices;
 
public class MyClass
{
        [DllImport(""kernel32.dll"")]
        public static extern IntPtr GetConsoleWindow();
}");
        }
 
        private static DiagnosticResult GetCA1024CSharpResultAt(int line, int column, string methodName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyCS.Diagnostic()
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(methodName);
 
        private static DiagnosticResult GetCA1024BasicResultAt(int line, int column, string methodName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyVB.Diagnostic()
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(methodName);
    }
}