File: Microsoft.CodeQuality.Analyzers\ApiDesignGuidelines\UriParametersShouldNotBeStringsTests.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.UriParametersShouldNotBeStringsAnalyzer,
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.UriParametersShouldNotBeStringsFixer>;
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.UriParametersShouldNotBeStringsAnalyzer,
    Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.UriParametersShouldNotBeStringsFixer>;
 
namespace Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines.UnitTests
{
    public class UriParametersShouldNotBeStringsTests
    {
        [Fact]
        public async Task CA1054NoWarningWithUrlNotStringTypeAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    public class A
    {
        public static void Method(int url) { }
    }
");
        }
 
        [Fact]
        public async Task CA1054WarningWithUrlAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    public class A
    {
        public static void Method(string url) { }
    }
", GetCA1054CSharpResultAt(6, 42, "url", "A.Method(string)"));
        }
 
        [Fact]
        public async Task CA1054NoWarningWithUrlWithOverloadAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    public class A
    {
        public static void Method(string url) { }
        public static void Method(Uri url) { }
    }
");
        }
 
        [Fact, WorkItem(1495, "https://github.com/dotnet/roslyn-analyzers/issues/1495")]
        public async Task CA1054NoWarningWithUrlWithOverload_IdenticalTypeParametersAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    public class A
    {
        // Identical type parameters with no constraints
        public static void Method1<T>(string url, T param2) { }
        public static void Method1<V>(Uri url, V param2) { }
 
        // Identical type parameters with differing constraints, we consider them identical for our comparison purpose.
        public static void Method2<T>(string url, T param2) where T : class { }
        public static void Method2<V>(Uri url, V param2) where V : struct { }
 
        // Identical constructed types.
        public static void Method3<T>(string url, B<T> param2) { }
        public static void Method3<V>(Uri url, B<V> param2) { }
    }
 
    public class B<T> { }
");
        }
 
        [Fact, WorkItem(1495, "https://github.com/dotnet/roslyn-analyzers/issues/1495")]
        public async Task CA1054WarningWithUrlWithOverload_DifferingTypeParametersAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    public class A
    {
        // Type parameters differing ordinal
        public static void Method1<T1, T2>(string url, T1 param2) { }
        public static void Method1<V1, V2>(Uri url, V2 param2) { }
 
        // Different constructed types.
        public static void Method2<T>(string url, B<T> param2) { }
        public static void Method2<V>(Uri url, C<V> param2) { }
    }
 
    public class B<T> { }
    public class C<T> { }
",
            // Test0.cs(7,51): warning CA1054: Change the type of parameter url of method A.Method1<T1, T2>(string, T1) from string to System.Uri, or provide an overload to A.Method1<T1, T2>(string, T1) that allows url to be passed as a System.Uri object.
            GetCA1054CSharpResultAt(7, 51, "url", "A.Method1<T1, T2>(string, T1)"),
            // Test0.cs(11,46): warning CA1054: Change the type of parameter url of method A.Method2<T>(string, B<T>) from string to System.Uri, or provide an overload to A.Method2<T>(string, B<T>) that allows url to be passed as a System.Uri object.
            GetCA1054CSharpResultAt(11, 46, "url", "A.Method2<T>(string, B<T>)"));
        }
 
        [Fact]
        public async Task CA1054MultipleWarningWithUrlAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    public class A
    {
        public static void Method(string url, string url2) { }
    }
", GetCA1054CSharpResultAt(6, 42, "url", "A.Method(string, string)")
 , GetCA1054CSharpResultAt(6, 54, "url2", "A.Method(string, string)"));
        }
 
        [Fact]
        public async Task CA1054NoMultipleWarningWithUrlWithOverloadAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    public class A
    {
        public static void Method(string url, string url2) { }
        public static void Method(string url, Uri url2) { }
        public static void Method(Uri url, string url2) { }
        public static void Method(Uri url, Uri url2) { }
    }
");
        }
 
        [Fact]
        public async Task CA1054MultipleWarningWithUrlWithOverloadAsync()
        {
            // Following original FxCop implementation. but this seems strange.
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    public class A
    {
        public static void Method(string url, string url2) { }
        public static void Method(Uri url, Uri url2) { }
    }
", GetCA1054CSharpResultAt(6, 42, "url", "A.Method(string, string)")
 , GetCA1054CSharpResultAt(6, 54, "url2", "A.Method(string, string)"));
 
        }
 
        [Fact, WorkItem(6371, "https://github.com/dotnet/roslyn-analyzers/issues/6371")]
        public async Task CA1054NoWarningsForInterfaceImplementationsAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    public interface IUrlInterface1
    {
        void Method(string url);
    }
 
    public interface IUrlInterface2
    {
        void Method(string url);
    }
 
    public class A : IUrlInterface1, IUrlInterface2
    {
        public void Method(string url) // Implements IUrlInterface1, implicitly
        {
        }
 
        void IUrlInterface2.Method(string url) // Implements IUrlInterface2, explicitly
        {
        }
    }
", GetCA1054CSharpResultAt(6, 28, "url", "IUrlInterface1.Method(string)")
 , GetCA1054CSharpResultAt(11, 28, "url", "IUrlInterface2.Method(string)"));
        }
 
        [Fact]
        public async Task CA1054NoWarningNotPublicAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    internal class A
    {
        public static void Method(string url) { }
    }
");
        }
 
        [Fact]
        public async Task CA1054NoWarningDerivedFromAttributeAsync()
        {
            await VerifyCS.VerifyAnalyzerAsync(@"
    using System;
 
    internal class A : Attribute
    {
        public void Method(string url) { }
    }
");
        }
 
        [Fact]
        public async Task CA1054WarningVBAsync()
        {
            // C# and VB shares same implementation. so just one vb test
            await VerifyVB.VerifyAnalyzerAsync(@"
    Imports System
    
    Public Module A
        Public Sub Method(firstUri As String)
        End Sub
    End Module
", GetCA1054BasicResultAt(5, 27, "firstUri", "A.Method(String)"));
        }
 
        [Theory, WorkItem(6005, "https://github.com/dotnet/roslyn-analyzers/issues/6005")]
        [InlineData("")]
        [InlineData("dotnet_code_quality.excluded_symbol_names = Method")]
        [InlineData("dotnet_code_quality.CA1054.excluded_symbol_names = Method")]
        [InlineData("dotnet_code_quality.CA1054.excluded_symbol_names = Metho*")]
        public async Task CA1054_EditorConfigConfiguration_ExcludedSymbolNamesWithValueOptionAsync(string editorConfigText)
        {
            var csharpTest = new VerifyCS.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
using System;
 
public class A
{
    public static void Method(string url) { }
}
"                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
 
[*]
{editorConfigText}
") }
                }
            };
 
            if (editorConfigText.Length == 0)
            {
                csharpTest.ExpectedDiagnostics.Add(GetCA1054CSharpResultAt(6, 38, "url", "A.Method(string)"));
            }
 
            await csharpTest.RunAsync();
 
            var basicTest = new VerifyVB.Test
            {
                TestState =
                {
                    Sources =
                    {
                        @"
Imports System
 
Public Module A
    Public Sub Method(url As String)
    End Sub
End Module"
                    },
                    AnalyzerConfigFiles = { ("/.editorconfig", $@"root = true
 
[*]
{editorConfigText}
") }
                }
            };
 
            if (editorConfigText.Length == 0)
            {
                basicTest.ExpectedDiagnostics.Add(GetCA1054BasicResultAt(5, 23, "url", "A.Method(String)"));
            }
 
            await basicTest.RunAsync();
        }
 
        private static DiagnosticResult GetCA1054CSharpResultAt(int line, int column, params string[] args)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyCS.Diagnostic()
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(args);
 
        private static DiagnosticResult GetCA1054BasicResultAt(int line, int column, params string[] args)
#pragma warning disable RS0030 // Do not use banned APIs
            => VerifyVB.Diagnostic()
                .WithLocation(line, column)
#pragma warning restore RS0030 // Do not use banned APIs
                .WithArguments(args);
    }
}