File: Microsoft.CodeQuality.Analyzers\QualityGuidelines\UseLiteralsWhereAppropriateTests.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;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Testing;
using Test.Utilities;
using Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.CodeQuality.CSharp.Analyzers.QualityGuidelines.CSharpUseLiteralsWhereAppropriate,
    Microsoft.CodeQuality.CSharp.Analyzers.QualityGuidelines.CSharpUseLiteralsWhereAppropriateFixer>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.CodeQuality.VisualBasic.Analyzers.QualityGuidelines.BasicUseLiteralsWhereAppropriate,
    Microsoft.CodeQuality.VisualBasic.Analyzers.QualityGuidelines.BasicUseLiteralsWhereAppropriateFixer>;
 
namespace Microsoft.CodeQuality.Analyzers.QualityGuidelines.UnitTests
{
    public class UseLiteralsWhereAppropriateTests
    {
        [Fact]
        public async Task CA1802_Diagnostics_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class Class1
{
    static readonly string f1 = """";
    static readonly string f2 = ""Nothing"";
    static readonly string f3,f4 = ""Message is shown only for f4"";
    static readonly int f5 = 3;
    const int f6 = 3;
    static readonly int f7 = 8 + f6;
    internal static readonly int f8 = 8 + f6;
}",
                GetCSharpEmptyStringResultAt(line: 4, column: 28, symbolName: "f1"),
                GetCSharpDefaultResultAt(line: 5, column: 28, symbolName: "f2"),
                GetCSharpDefaultResultAt(line: 6, column: 31, symbolName: "f4"),
                GetCSharpDefaultResultAt(line: 7, column: 25, symbolName: "f5"),
                GetCSharpDefaultResultAt(line: 9, column: 25, symbolName: "f7"),
                GetCSharpDefaultResultAt(line: 10, column: 34, symbolName: "f8"));
        }
 
        [Fact]
        public async Task CA1802_NoDiagnostics_CSharpAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
public class Class1
{
    public static readonly string f1 = """"; // Not private or Internal
    static string f3, f4 = ""Message is shown only for f4""; // Not readonly
    readonly int f5 = 3; // Not static
    const int f6 = 3; // Is already const
    static int f9 = getF9();
    static readonly int f7 = 8 + f9; // f9 is not a const
    static readonly string f8 = null; // null value
 
    private static int getF9()
    {
        throw new System.NotImplementedException();
    }
}");
        }
 
        [Fact]
        public async Task CA1802_Diagnostics_VisualBasicAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Class Class1
    Shared ReadOnly f1 As String = """"
    Shared ReadOnly f2 As String = ""Nothing""
    Shared ReadOnly f3 As String, f4 As String = ""Message is shown only for f4""
    Shared ReadOnly f5 As Integer = 3
    Const f6 As Integer = 3
    Shared ReadOnly f7 As Integer = 8 + f6
    Friend Shared ReadOnly f8 As Integer = 8 + f6
End Class",
                GetBasicEmptyStringResultAt(line: 3, column: 21, symbolName: "f1"),
                GetBasicDefaultResultAt(line: 4, column: 21, symbolName: "f2"),
                GetBasicDefaultResultAt(line: 5, column: 35, symbolName: "f4"),
                GetBasicDefaultResultAt(line: 6, column: 21, symbolName: "f5"),
                GetBasicDefaultResultAt(line: 8, column: 21, symbolName: "f7"),
                GetBasicDefaultResultAt(line: 9, column: 28, symbolName: "f8"));
        }
 
        [Fact]
        public async Task CA1802_NoDiagnostics_VisualBasicAsync()
        {
            await VerifyVB.VerifyAnalyzerAsync(@"
Public Class Class1
    ' Not Private or Friend
    Public Shared ReadOnly f1 As String = """"
    ' Not Readonly
    Shared f3 As String, f4 As String = ""Message is shown only for f4""
    ' Not Shared
    ReadOnly f5 As Integer = 3
    ' Is already Const
    Const f6 As Integer = 3
    Shared f9 As Integer = getF9()
    ' f9 is not a Const
    Shared ReadOnly f7 As Integer = 8 + f9
    ' null value
    Shared ReadOnly f8 As String = Nothing
 
    Private Shared Function getF9() As Integer
        Throw New System.NotImplementedException()
    End Function
End Class");
        }
 
        [Theory]
        [WorkItem(2772, "https://github.com/dotnet/roslyn-analyzers/issues/2772")]
        [InlineData("", false)]
        [InlineData("dotnet_code_quality.required_modifiers = static", false)]
        [InlineData("dotnet_code_quality.required_modifiers = none", true)]
        [InlineData("dotnet_code_quality." + UseLiteralsWhereAppropriateAnalyzer.RuleId + ".required_modifiers = none", true)]
        public async Task EditorConfigConfiguration_RequiredModifiersOptionAsync(string editorConfigText, bool reportDiagnostic)
        {
            var expected = Array.Empty<DiagnosticResult>();
            if (reportDiagnostic)
            {
                expected = new[]
                {
                    GetCSharpDefaultResultAt(4, 26, "field")
                };
            }
 
            var csTest = new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
public class Test
{
    private readonly int field = 0;
}
"
                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
 
[*]
{editorConfigText}
") }
                },
            };
            csTest.ExpectedDiagnostics.AddRange(expected);
            await csTest.RunAsync();
 
            expected = Array.Empty<DiagnosticResult>();
            if (reportDiagnostic)
            {
                expected = new[]
                {
                    GetBasicDefaultResultAt(3, 22, "field")
                };
            }
 
            var vbTest = new VerifyVB.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
Public Class Test
    Private ReadOnly field As Integer = 0
End Class
"
                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
 
[*]
{editorConfigText}
") }
                }
            };
            vbTest.ExpectedDiagnostics.AddRange(expected);
            await vbTest.RunAsync();
        }
 
        [Fact]
        public async Task CA1802_CSharp_IntPtr_UIntPtr_NoDiagnosticAsync()
        {
            await new VerifyCS.Test
            {
                LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9,
                ReferenceAssemblies = ReferenceAssemblies.Net.Net50,
                TestCode = @"
using System;
 
public class Class1
{
	internal static readonly IntPtr field1 = (nint)0;
	internal static readonly UIntPtr field2 = (nuint)0;
}",
            }.RunAsync();
        }
 
        [Fact]
        public async Task CA1802_CSharp_nint_DiagnosticAsync()
        {
            await new VerifyCS.Test
            {
                LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9,
                ReferenceAssemblies = ReferenceAssemblies.Net.Net50,
                TestCode = @"
using System;
 
public class Class1
{
    internal static readonly nint field = (nint)0;
}",
                ExpectedDiagnostics =
                {
                    GetCSharpDefaultResultAt(6, 35, "field"),
                },
                FixedCode = @"
using System;
 
public class Class1
{
    internal const nint field = (nint)0;
}",
            }.RunAsync();
        }
 
        [Fact]
        public async Task CA1802_CSharp_nuint_DiagnosticAsync()
        {
            await new VerifyCS.Test
            {
                LanguageVersion = CodeAnalysis.CSharp.LanguageVersion.CSharp9,
                ReferenceAssemblies = ReferenceAssemblies.Net.Net50,
                TestCode = @"
using System;
 
public class Class1
{
    internal static readonly nuint field = (nuint)0;
}",
                ExpectedDiagnostics =
                {
                    GetCSharpDefaultResultAt(6, 36, "field"),
                },
                FixedCode = @"
using System;
 
public class Class1
{
    internal const nuint field = (nuint)0;
}",
            }.RunAsync();
        }
 
        [Fact, WorkItem(6681, "https://github.com/dotnet/roslyn-analyzers/issues/6681")]
        public Task CA1802_CSharp_EnumsWithSameNameAsField_NoDiagnosticAsync()
        {
            return new VerifyCS.Test
            {
                TestCode = @"
using System.Reflection;
 
public class Class
{
    private static readonly BindingFlags BindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
}"
            }.RunAsync();
        }
 
        [Fact, WorkItem(6681, "https://github.com/dotnet/roslyn-analyzers/issues/6681")]
        public Task CA1802_CSharp_EnumsWithSameNameAsField2_NoDiagnosticAsync()
        {
            return new VerifyCS.Test
            {
                TestCode = @"
using System.Reflection;
 
public class Class
{
    private static readonly BindingFlags BindingFlags = (BindingFlags)(BindingFlags.Public | BindingFlags.NonPublic);
}"
            }.RunAsync();
        }
 
        [Fact, WorkItem(6681, "https://github.com/dotnet/roslyn-analyzers/issues/6681")]
        public Task CA1802_CSharp_EnumsWithDifferentNameAsField_DiagnosticAsync()
        {
            return new VerifyCS.Test
            {
                TestCode = @"
using System.Reflection;
 
public class Class
{
    private static readonly BindingFlags {|#0:B|} = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
}",
                FixedCode = @"
using System.Reflection;
 
public class Class
{
    private const BindingFlags B = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
}",
                ExpectedDiagnostics = { new DiagnosticResult(UseLiteralsWhereAppropriateAnalyzer.DefaultRule).WithLocation(0).WithArguments("B") }
            }.RunAsync();
        }
 
        [Fact, WorkItem(6681, "https://github.com/dotnet/roslyn-analyzers/issues/6681")]
        public Task CA1802_CSharp_EnumsWithSameNameAsField_DiagnosticAsync()
        {
            return new VerifyCS.Test
            {
                TestCode = @"
using System.Reflection;
 
public class Class
{
    private static readonly BindingFlags {|#0:BindingFlags|} = (BindingFlags)5;
}",
                FixedCode = @"
using System.Reflection;
 
public class Class
{
    private const BindingFlags BindingFlags = (BindingFlags)5;
}",
                ExpectedDiagnostics = { new DiagnosticResult(UseLiteralsWhereAppropriateAnalyzer.DefaultRule).WithLocation(0).WithArguments("BindingFlags") }
            }.RunAsync();
        }
 
        private static DiagnosticResult GetCSharpDefaultResultAt(int line, int column, string symbolName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyCS.Diagnostic(UseLiteralsWhereAppropriateAnalyzer.DefaultRule)
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(symbolName);
 
        private static DiagnosticResult GetCSharpEmptyStringResultAt(int line, int column, string symbolName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyCS.Diagnostic(UseLiteralsWhereAppropriateAnalyzer.EmptyStringRule)
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(symbolName);
 
        private static DiagnosticResult GetBasicDefaultResultAt(int line, int column, string symbolName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyVB.Diagnostic(UseLiteralsWhereAppropriateAnalyzer.DefaultRule)
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(symbolName);
 
        private static DiagnosticResult GetBasicEmptyStringResultAt(int line, int column, string symbolName)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyVB.Diagnostic(UseLiteralsWhereAppropriateAnalyzer.EmptyStringRule)
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(symbolName);
    }
}