File: Microsoft.CodeQuality.Analyzers\ApiDesignGuidelines\OperatorOverloadsHaveNamedAlternatesTests.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.OperatorOverloadsHaveNamedAlternatesAnalyzer,
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.OperatorOverloadsHaveNamedAlternatesFixer>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.OperatorOverloadsHaveNamedAlternatesAnalyzer,
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.OperatorOverloadsHaveNamedAlternatesFixer>;
 
namespace Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.UnitTests
{
    public class OperatorOverloadsHaveNamedAlternatesTests
    {
        #region Boilerplate
 
        private static DiagnosticResult GetCA2225CSharpDefaultResultAt(int line, int column, string alternateName, string operatorName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.DefaultRule)
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(alternateName, operatorName);
 
        private static DiagnosticResult GetCA2225CSharpPropertyResultAt(int line, int column, string alternateName, string operatorName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.PropertyRule)
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(alternateName, operatorName);
 
        private static DiagnosticResult GetCA2225CSharpMultipleResultAt(int line, int column, string alternateName1, string alternateName2, string operatorName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.MultipleRule)
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(alternateName1, alternateName2, operatorName);
 
        private static DiagnosticResult GetCA2225CSharpVisibilityResultAt(int line, int column, string alternateName, string operatorName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.VisibilityRule)
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(alternateName, operatorName);
 
        private static DiagnosticResult GetCA2225BasicDefaultResultAt(int line, int column, string alternateName, string operatorName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyVB.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.DefaultRule)
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(alternateName, operatorName);
 
        #endregion
 
        #region C# tests
 
        [Fact]
        public async Task HasAlternateMethod_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
    public static C operator +(C left, C right) { return new C(); }
    public static C Add(C left, C right) { return new C(); }
}
");
        }
 
        [Fact]
        public async Task HasMultipleAlternatePrimary_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
    public static C operator %(C left, C right) { return new C(); }
    public static C Mod(C left, C right) { return new C(); }
}
");
        }
 
        [Fact]
        public async Task HasMultipleAlternateSecondary_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
    public static C operator %(C left, C right) { return new C(); }
    public static C Remainder(C left, C right) { return new C(); }
}
");
        }
 
        [Fact]
        public async Task HasAppropriateConversionAlternate_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
    public static implicit operator int(C item) { return 0; }
    public int ToInt32() { return 0; }
}
");
        }
 
        [Fact, WorkItem(1717, "https://github.com/dotnet/roslyn-analyzers/issues/1717")]
        public async Task HasAppropriateConversionAlternate02_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class Other
{	
	public int i {get; set;}
 
	public Other(int i) => this.i = i;	
}
 
public class SomeClass
{	
	public int i {get; set;}
 
	public SomeClass(int i) => this.i = i;
 
	public static implicit operator SomeClass(Other b) => new SomeClass(b.i);
 
	public static SomeClass FromOther(Other b) => new SomeClass(b.i);
}
");
        }
 
        [Fact]
        public async Task MissingAlternateMethod_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
    public static C operator +(C left, C right) { return new C(); }
}
",
            GetCA2225CSharpDefaultResultAt(4, 30, "Add", "op_Addition"));
        }
 
        [Fact, WorkItem(1432, "https://github.com/dotnet/roslyn-analyzers/issues/1432")]
        public async Task MissingAlternateMethod_CSharp_InternalAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
class C
{
    public static C operator +(C left, C right) { return new C(); }
}
 
public class C2
{
    private class C3
    {
        public static C3 operator +(C3 left, C3 right) { return new C3(); }
    }
}
");
        }
 
        [Fact]
        public async Task MissingAlternateProperty_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
    public static bool operator true(C item) { return true; }
    public static bool operator false(C item) { return false; }
}
",
            GetCA2225CSharpPropertyResultAt(4, 33, "IsTrue", "op_True"));
        }
 
        [Fact]
        public async Task MissingMultipleAlternates_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
    public static C operator %(C left, C right) { return new C(); }
}
",
            GetCA2225CSharpMultipleResultAt(4, 30, "Mod", "Remainder", "op_Modulus"));
        }
 
        [Fact]
        public async Task ImproperAlternateMethodVisibility_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
    public static C operator +(C left, C right) { return new C(); }
    protected static C Add(C left, C right) { return new C(); }
}
",
                GetCA2225CSharpVisibilityResultAt(5, 24, "Add", "op_Addition"));
        }
 
        [Fact]
        public async Task ImproperAlternatePropertyVisibility_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class C
{
    public static bool operator true(C item) { return true; }
    public static bool operator false(C item) { return false; }
    private bool IsTrue => true;
}
",
            GetCA2225CSharpVisibilityResultAt(6, 18, "IsTrue", "op_True"));
        }
 
        [Fact]
        public async Task StructHasAlternateMethod_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
struct C
{
    public static C operator +(C left, C right) { return new C(); }
    public static C Add(C left, C right) { return new C(); }
}
");
        }
 
        [Fact]
        public async Task ImplicitCastToArrayAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(
@"
public struct MyStruct
{
    public static implicit operator byte[](MyStruct myStruct)
    {
        return new byte[1];
    }
}",
                VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.MultipleRule).WithSpan(4, 37, 4, 43).WithArguments("ToByteArray", "FromMyStruct", "op_Implicit"));
        }
 
        [Fact]
        public async Task ExplicitCastToArrayAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(
@"
public struct MyStruct
{
    public static explicit operator byte[](MyStruct myStruct)
    {
        return new byte[1];
    }
}",
                VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.MultipleRule).WithSpan(4, 37, 4, 43).WithArguments("ToByteArray", "FromMyStruct", "op_Explicit"));
        }
 
        [Fact]
        public async Task ImplicitCastToMultidimensionalArrayAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(
@"
public struct MyStruct
{
    public static implicit operator byte[,](MyStruct myStruct)
    {
        return new byte[1,1];
    }
}",
                VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.MultipleRule).WithSpan(4, 37, 4, 44).WithArguments("ToByteArray", "FromMyStruct", "op_Implicit"));
        }
 
        [Fact]
        public async Task ExplicitCastToMultidimensionalArrayAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(
@"
public struct MyStruct
{
    public static explicit operator byte[,](MyStruct myStruct)
    {
        return new byte[1,1];
    }
}",
                VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.MultipleRule).WithSpan(4, 37, 4, 44).WithArguments("ToByteArray", "FromMyStruct", "op_Explicit"));
        }
 
        [Fact]
        public async Task ImplicitCastToJaggedArrayAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(
@"
public struct MyStruct
{
    public static implicit operator byte[][](MyStruct myStruct)
    {
        return new byte[1][];
    }
}",
                VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.MultipleRule).WithSpan(4, 37, 4, 45).WithArguments("ToByteArray", "FromMyStruct", "op_Implicit"));
        }
 
        [Fact]
        public async Task ExplicitCastToJaggedArrayAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(
@"
public struct MyStruct
{
    public static explicit operator byte[][](MyStruct myStruct)
    {
        return new byte[1][];
    }
}",
                VerifyCS.Diagnostic(OperatorOverloadsHaveNamedAlternatesAnalyzer.MultipleRule).WithSpan(4, 37, 4, 45).WithArguments("ToByteArray", "FromMyStruct", "op_Explicit"));
        }
 
        #endregion
 
        //
        // Since the analyzer is symbol-based, only a few VB tests are added as a sanity check
        //
 
        #region VB tests
 
        [Fact]
        public async Task HasAlternateMethod_VisualBasicAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Class C
    Public Shared Operator +(left As C, right As C) As C
        Return New C()
    End Operator
    Public Shared Function Add(left As C, right As C) As C
        Return New C()
    End Function
End Class
");
        }
 
        [Fact]
        public async Task MissingAlternateMethod_VisualBasicAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Class C
    Public Shared Operator +(left As C, right As C) As C
        Return New C()
    End Operator
End Class
",
            GetCA2225BasicDefaultResultAt(3, 28, "Add", "op_Addition"));
        }
 
        [Fact, WorkItem(1432, "https://github.com/dotnet/roslyn-analyzers/issues/1432")]
        public async Task MissingAlternateMethod_VisualBasic_InternalAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Class C
    Public Shared Operator +(left As C, right As C) As C
        Return New C()
    End Operator
End Class
 
Public Class C2
    Private Class C3
        Public Shared Operator +(left As C3, right As C3) As C3
            Return New C3()
        End Operator
    End Class
End Class
");
        }
 
        [Fact]
        public async Task StructHasAlternateMethod_VisualBasicAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Structure C
    Public Shared Operator +(left As C, right As C) As C
        Return New C()
    End Operator
    Public Shared Function Add(left As C, right As C) As C
        Return New C()
    End Function
End Structure
");
        }
 
        #endregion
    }
}