File: Microsoft.NetCore.Analyzers\InteropServices\UseValidPlatformStringTest.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 Xunit;
using VerifyCS = Test.Utilities.CSharpCodeFixVerifier<
    Microsoft.NetCore.Analyzers.InteropServices.UseValidPlatformString,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
 
using VerifyVB = Test.Utilities.VisualBasicCodeFixVerifier<
    Microsoft.NetCore.Analyzers.InteropServices.UseValidPlatformString,
    Microsoft.CodeAnalysis.Testing.EmptyCodeFixProvider>;
 
namespace Microsoft.NetCore.Analyzers.InteropServices.UnitTests
{
    public class UseValidPlatformStringTest
    {
        private const string s_msBuildPlatforms = @"is_global = true
build_property._SupportedPlatformList=CustomPlatform";
 
        [Fact]
        public async Task ValidPlatformStringUsedNotWarnAsync()
        {
            var csSource = @"
using System;
using System.Runtime.Versioning;
 
public class Test
{
    [SupportedOSPlatform(""Browser"")]
    public void SupportedBrowser() { }
 
    [SupportedOSPlatform(""iOS"")]
    public string SupportedIos => string.Empty;
 
    [UnsupportedOSPlatform(""linux"")]
    public void UnsupportedLinux() { }
 
    [SupportedOSPlatform(""Android"")]
    public event EventHandler AndroidOnlyEvent;
 
    [UnsupportedOSPlatform(""macos"")]
    public void UnsupportedMacOS() { }
 
    [SupportedOSPlatform(""TVOS"")]
    public Test() { }
 
    [SupportedOSPlatform(""freeBsd2.0.1.2"")]
    public void SupportedFreeBsd() { }
 
    [SupportedOSPlatform(""watchOS3.2.1"")]
    public void SupporteWatchOS() { }
 
    [UnsupportedOSPlatform(""windows7.0"")]
    public static void SupportedWindows() { }
}";
            await VerifyAnalyzerCsAsync(csSource);
        }
 
        [Fact]
        public async Task ValidPlatformStringUsedNotWarnVBAsync()
        {
            var vbSource = @"
Imports System.Runtime.Versioning
 
Public Class Test
    <SupportedOSPlatform(""Browser"")>
    Public Sub SupportedBrowser()
    End Sub
 
    <SupportedOSPlatform(""iOS"")>
    Public Sub SupportedIos()
    End Sub
 
    <UnsupportedOSPlatform(""linux"")>
    Public Sub UnsupportedLinux()
    End Sub
 
    <SupportedOSPlatform(""Android"")>
    Public Sub SupportedAndroid()
    End Sub
 
    <UnsupportedOSPlatform(""macos"")>
    Public Sub UnsupportedMacOS()
    End Sub
 
    <SupportedOSPlatform(""tvos"")>
    Public Sub SupportedTvOS()
    End Sub
 
    <SupportedOSPlatform(""freeBsd2.0.1.2"")>
    Public Sub SupportedFreeBsd()
    End Sub
 
    <SupportedOSPlatform(""watchOS3.2.1"")>
    Public Sub SupporteWatchOS()
    End Sub
 
    <UnsupportedOSPlatform(""WINDOWS7.0"")>
    Public Shared Sub SupportedWindows()
    End Sub
End Class";
            await VerifyAnalyzerAsyncVbAsync(vbSource);
        }
 
        [Fact]
        public async Task InvalidPlatformNameOrVersionWarnsAsync()
        {
            var csSource = @"
using System.Runtime.Versioning;
 
public class Test
{
    [{|#0:UnsupportedOSPlatform(""window7.0"")|}] // The platform 'window' is not a known platform name
    public void InvlaidPlatform() { }
 
    [{|#1:SupportedOSPlatform(""watch7.0"")|}] // The platform 'watch' is not a known platform name
    public void InvlaidPlatform2() { }
 
    [{|#2:UnsupportedOSPlatform(""windows7"")|}] // Version '7' is not valid for platform 'windows'. Use a version with 2-4 parts for this platform.
    public static void InvalidVersion() { }
 
    [{|#3:SupportedOSPlatform(""watchOs7.1.0.2"")|}] // Version '7.1.0.2' is not valid for platform 'watchOs'. Use a version with 2-3 parts for this platform.
    public static void InvalidVersion2() { }
 
    [{|#4:UnsupportedOSPlatform(""linux1.0."")|}] // Version '1.0.' is not valid for platform 'linux'. Do not use versions for this platform.
    public static void InvalidVersion3() { }
}";
            await VerifyAnalyzerCsAsync(csSource,
                VerifyCS.Diagnostic(UseValidPlatformString.UnknownPlatform).WithLocation(0).WithArguments("window"),
                VerifyCS.Diagnostic(UseValidPlatformString.UnknownPlatform).WithLocation(1).WithArguments("watch"),
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(2).WithArguments("7", "windows", "-4"),
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(3).WithArguments("7.1.0.2", "watchOs", "-3"),
                VerifyCS.Diagnostic(UseValidPlatformString.NoVersion).WithLocation(4).WithArguments("1.0.", "linux"));
        }
 
        [Fact]
        public async Task InvalidPlatformNameOrVersionWarnsVBAsync()
        {
            var vbSource = @"
Imports System.Runtime.Versioning
 
Public Class Test
    <[|UnsupportedOSPlatform(""window7.0"")|]>
    Public Sub InvlaidPlatform()
    End Sub
 
    <[|SupportedOSPlatform(""watch7.0"")|]>
    Public Sub InvlaidPlatform2()
    End Sub
 
    <[|UnsupportedOSPlatform(""windows7"")|]>
    Public Shared Sub InvalidVersion()
    End Sub
 
    <[|SupportedOSPlatform(""watchOs7.1.0.2.3"")|]>
    Public Shared Sub InvalidVersion2()
    End Sub
 
    <[|UnsupportedOSPlatform(""linux1.0."")|]>
    Public Shared Sub InvalidVersion3()
    End Sub
End Class";
            await VerifyAnalyzerAsyncVbAsync(vbSource);
        }
 
        [Fact]
        public async Task InvalidPlatformNameOrVersionDifferentSymbolsWarnsAsync()
        {
            var csSource = @"
using System;
using System.Runtime.Versioning;
 
[assembly:[|UnsupportedOSPlatform(""blazor"")|]] // The platform 'blazor' is not a known platform name
namespace ns
{
    [[|UnsupportedOSPlatform(""razor"")|]] // The platform 'razor' is not a known platform name
    public class Test
    {
        [[|UnsupportedOSPlatform(""window7.0"")|]] // The platform 'window' is not a known platform name
        public string InvlaidPlatform => string.Empty;
 
        [[|SupportedOSPlatform(""watch7.0"")|]] // The platform 'watch' is not a known platform name
        public Test() { }
 
        [[|UnsupportedOSPlatform(""windows7"")|]] // Version '7' is not valid for platform 'windows'. Use a version with 2-4 parts for this platform.
        public event EventHandler Windows7Event;
 
        [[|SupportedOSPlatform(""watchOs7.1.0.2.3"")|]] // Version '7.1.0.2.3' is not valid for platform 'watchOs'. Use a version with 2-3 parts for this platform.
        private static int s_field = 0;
    }
}";
            await VerifyAnalyzerCsAsync(csSource);
        }
 
        [Fact]
        public async Task NotWarnForCustomPlatformAddedToMsBuildAsync()
        {
            var csSource = @"
using System.Runtime.Versioning;
 
public class Test
{
    [SupportedOSPlatform(""customPlatform"")]
    public void SupportedCustomPlatform() { }
 
    [SupportedOSPlatform(""customplatform1.0"")]
    public void SupportedCustomPlatform1() { }
 
    [UnsupportedOSPlatform(""customPlatform2.0"")]
    public void UnsupportedCustomPlatform2() { }
 
    [UnsupportedOSPlatform(""customplatform"")]
    public void UnsupportedCustomPlatform() { }
 
    [[|UnsupportedOSPlatform(""custom1.0"")|]] // The platform 'custom' is not a known platform name
    public void InvlaidPlatform() { }
}";
            await VerifyAnalyzerCsAsync(csSource, s_msBuildPlatforms);
        }
 
        [Fact]
        public async Task NotWarnForCustomPlatformAddedToMsBuildVBAsync()
        {
            var vbSource = @"
Imports System.Runtime.Versioning
 
Public Class Test
    <SupportedOSPlatform(""customPlatform"")>
    Public Sub SupportedCustomPlatform()
    End Sub
 
    <SupportedOSPlatform(""customplatform1.0"")>
    Public Sub SupportedCustomPlatform1()
    End Sub
 
    <UnsupportedOSPlatform(""customPlatform2.0"")>
    Public Sub UnsupportedCustomPlatform2()
    End Sub
 
    <UnsupportedOSPlatform(""customplatform"")>
    Public Sub UnsupportedCustomPlatform()
    End Sub
 
    <[|UnsupportedOSPlatform(""custom1.0"")|]>
    Public Sub InvlaidPlatform()
    End Sub
End Class";
            await VerifyAnalyzerAsyncVbAsync(vbSource, s_msBuildPlatforms);
        }
 
        [Fact]
        public async Task IsOsPlatformWithInvalidPlatformWarnsAsync()
        {
            var csSource = @"
using System;
using System.Runtime.Versioning;
using System.Diagnostics;
 
public class Test
{
    public void M1()
    {
        if (OperatingSystem.IsOSPlatform([|""x""|])) // The platform 'x' is not a known platform name
            PlatformSpecificAPI();
 
        if (OperatingSystem.IsOSPlatformVersionAtLeast([|""x""|], 1)) // The platform 'x' is not a known platform name
            PlatformSpecificAPI();
 
        if (!OperatingSystem.IsOSPlatformVersionAtLeast([|""window""|], 8, 100)) // The platform 'window' is not a known platform name
            PlatformSpecificAPI();
 
        if (!OperatingSystem.IsOSPlatformVersionAtLeast([|""xPlatform""|], 1, 2, 3, 4)) // The platform 'xPlatform' is not a known platform name
            PlatformSpecificAPI();
 
        if (OperatingSystem.IsOSPlatform(""windows"")) // No warn
            PlatformSpecificAPI();
 
        if (OperatingSystem.IsOSPlatformVersionAtLeast(""ios"", 12, 100, 0, 1)) // No warn
            PlatformSpecificAPI();
 
        if (OperatingSystem.IsOSPlatform([|""windows8.0""|])) // Version part not allowed: The platform 'windows8.0' is not a known platform name
            PlatformSpecificAPI();
 
        Debug.Assert(OperatingSystem.IsOSPlatformVersionAtLeast([|""windows8.0""|], 1, 2, 3, 4));
        Debug.Assert(OperatingSystem.IsOSPlatform([|""invalid""|]));
    }
 
    public void PlatformSpecificAPI() { }
}";
            await VerifyAnalyzerCsAsync(csSource);
        }
 
        [Fact]
        public async Task IsOsPlatformWithInvalidPlatformWarnsVBAsync()
        {
            var vbSource = @"
Imports System
Imports System.Runtime.Versioning
 
Public Class Test
    Public Sub M1()
        If OperatingSystem.IsOSPlatform([|""x""|]) Then PlatformSpecificAPI()
        If OperatingSystem.IsOSPlatformVersionAtLeast([|""x""|], 1) Then PlatformSpecificAPI()
        If Not OperatingSystem.IsOSPlatformVersionAtLeast([|""window""|], 8, 100) Then PlatformSpecificAPI()
        If OperatingSystem.IsOSPlatform(""windows"") Then PlatformSpecificAPI()
        If OperatingSystem.IsOSPlatformVersionAtLeast(""ios"", 12, 100, 0, 1) Then PlatformSpecificAPI()
        If OperatingSystem.IsOSPlatform([|""windows8.0""|]) Then PlatformSpecificAPI()
    End Sub
 
    Public Sub PlatformSpecificAPI()
    End Sub
End Class";
            await VerifyAnalyzerAsyncVbAsync(vbSource);
        }
 
        [Fact]
        public async Task MoreInvalidPlatformStringsWarnsAsync()
        {
            var source = @"
using System.Runtime.Versioning;
 
public class Test
{
    [[|SupportedOSPlatform(""Ios-4.1"")|]]
    public void SupportedOSPlatformIosDash4_1() { }
 
    [[|UnsupportedOSPlatform(""Ios*4.1"")|]]
    public void UnsupportedOSPlatformIosStar4_1() { }
 
    [[|SupportedOSPlatform(null)|]]
    public void SupportedOSPlatformWithNullString() { }
 
    [[|SupportedOSPlatform(""Linux_4.1"")|]]
    public void SupportedLinux_41() { }
 
    [[|UnsupportedOSPlatform("""")|]]
    public void UnsupportedWithEmptyString() { }
}";
            await VerifyAnalyzerCsAsync(source);
        }
 
        [Fact]
        public async Task InvalidVersionPartInPlatformStringsWarnsAsync()
        {
            var source = @"
using System.Runtime.Versioning;
 
public class Test
{
    [{|#0:SupportedOSPlatform(""Android4.8.1.2.3"")|}] // Version '4.8.1.2.3' is not valid for platform 'Android'. Use a version with 2-4 parts for this platform.
    public void SupportedOSPlatformAndroid5Parts() { }
 
    [{|#1:UnsupportedOSPlatform(""Ios14.1.2.3"")|}] // Version '14.1.2.3' is not valid for platform 'Ios'. Use a version with 2-3 parts for this platform.
    public void UnsupportedOSPlatformIos4PartsInvalid() { }
 
    [{|#2:SupportedOSPlatform(""macos1.2.3.4.5"")|}] // Version '1.2.3.4.5' is not valid for platform 'macos'. Use a version with 2-3 parts for this platform.
    public void SupportedOSPlatformMac5PartsInvalid() { }
 
    [SupportedOSPlatform(""macos1.2.3"")]
    public void SupportedMacOs3PartValid() { }
 
    [SupportedOSPlatform(""tvos1.2.3"")]
    public void SupportedTvOs3PartValid() { }
 
    [{|#3:UnsupportedOSPlatform(""watchos1.2.3.4"")|}] // Version '1.2.3.4' is not valid for platform 'watchos'. Use a version with 2-3 parts for this platform.
    public void UnsupportedWatchOs4PartsInvalid() { }
 
    [{|#4:SupportedOSPlatform(""Linux4.1"")|}] // Version '4.1' is not valid for platform 'Linux'. Do not use versions for this platform.
    public void SupportedLinux_41() { }
}";
            await VerifyAnalyzerCsAsync(source,
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(0).WithArguments("4.8.1.2.3", "Android", "-4"),
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(1).WithArguments("14.1.2.3", "Ios", "-3"),
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(2).WithArguments("1.2.3.4.5", "macos", "-3"),
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(3).WithArguments("1.2.3.4", "watchos", "-3"),
                VerifyCS.Diagnostic(UseValidPlatformString.NoVersion).WithLocation(4).WithArguments("4.1", "Linux"));
        }
 
        [Fact]
        public async Task PlatformOSXIsAliasForMacOSAsync()
        {
            var csSource = @"
using System.Runtime.Versioning;
 
public class Test
{
    [{|#0:SupportedOSPlatform(""MacOS1.2.3.4"")|}] // Version '1.2.3.4' is not valid for platform 'MacOS'. Use a version with 2-3 parts for this platform.
    public void SupportedOSPlatformMac4PartsInvalid() { }
 
    [SupportedOSPlatform(""MacOS1.2"")]
    public void SupportedMacOs2PartsValid() { }
 
    [{|#1:SupportedOSPlatform(""OSX1.2.3.4"")|}] // Version '1.2.3.4' is not valid for platform 'OSX'. Use a version with 2-3 parts for this platform.
    public void SupportedOSPlatformOSX4PartsInvalid() { }
 
    [SupportedOSPlatform(""Osx1.2"")]
    public void SupportedOsx2PartsValid() { }
}";
            await VerifyAnalyzerCsAsync(csSource,
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(0).WithArguments("1.2.3.4", "MacOS", "-3"),
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(1).WithArguments("1.2.3.4", "OSX", "-3"));
        }
 
        [Fact]
        public async Task APIsWithMultiplePlatformSupportUnsupportAsync()
        {
            var csSource = @"
using System.Runtime.Versioning;
 
public class Test
{
    [{|#0:SupportedOSPlatform(""MacOS1.2.3.4"")|}] // Version '1.2.3.4' is not valid for platform 'MacOS'. Use a version with 2-3 parts for this platform.
    [SupportedOSPlatform(""Osx2.3"")]
    [SupportedOSPlatform(""Linux"")]
    [[|SupportedOSPlatform(""Linux4.3"")|]] // Linux should not have a version
    public void SupportedOSPlatformMac4PartsInvalid() { }
 
    [SupportedOSPlatform(""MacOS1.2"")]
    [SupportedOSPlatform(""Osx2.3"")]
    public void SupportedMacOsOsxPartsValid() { }
 
    [UnsupportedOSPlatform(""osx"")]
    [{|#1:SupportedOSPlatform(""OSX1.2.3.4"")|}] // Version '1.2.3.4' is not valid for platform 'OSX'. Use a version with 2-3 parts for this platform.
    [UnsupportedOSPlatform(""browser"")]
    public void UnsupportedBrowserOSXSupportHasWarning() { }
 
    [UnsupportedOSPlatform(""browser"")]
    [[|UnsupportedOSPlatform(""Linux1.0"")|]] // Linux should not have a version
    public void UnsupportedOSPlatformOSX4PartsInvalid() { }
 
    [SupportedOSPlatform(""Osx1.2"")]
    [[|SupportedOSPlatform(""MacOS1.2.3.4"")|]] // Version '1.2.3.4' is not valid for platform 'MacOS'. Use a version with 2-3 parts for this platform.
    public void SupportedOsx2PartValid() { }
}";
            await VerifyAnalyzerCsAsync(csSource,
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(0).WithArguments("1.2.3.4", "MacOS", "-3"),
                VerifyCS.Diagnostic(UseValidPlatformString.InvalidVersion).WithLocation(1).WithArguments("1.2.3.4", "OSX", "-3"));
        }
 
        private static async Task VerifyAnalyzerCsAsync(string sourceCode, params DiagnosticResult[] expectedDiagnostics)
        {
            var test = PopulateTestCs(sourceCode);
            test.ExpectedDiagnostics.AddRange(expectedDiagnostics);
            await test.RunAsync();
        }
 
        private static async Task VerifyAnalyzerCsAsync(string sourceCode, string editorconfigText)
        {
            var test = PopulateTestCs(sourceCode);
            test.TestState.AnalyzerConfigFiles.Add(("/.globalconfig", editorconfigText));
            await test.RunAsync();
        }
 
        private static VerifyCS.Test PopulateTestCs(string sourceCode)
        {
            return new VerifyCS.Test
            {
                TestCode = sourceCode,
                ReferenceAssemblies = ReferenceAssemblies.Net.Net50,
                MarkupOptions = MarkupOptions.UseFirstDescriptor,
            };
        }
 
        private static async Task VerifyAnalyzerAsyncVbAsync(string sourceCode)
        {
            var task = PopulateTestVb(sourceCode);
            await task.RunAsync();
        }
 
        private static async Task VerifyAnalyzerAsyncVbAsync(string sourceCode, string editorconfigText)
        {
            var test = PopulateTestVb(sourceCode);
            test.TestState.AnalyzerConfigFiles.Add(("/.globalconfig", editorconfigText));
            await test.RunAsync();
        }
 
        private static VerifyVB.Test PopulateTestVb(string sourceCode)
        {
            return new VerifyVB.Test
            {
                TestCode = sourceCode,
                ReferenceAssemblies = ReferenceAssemblies.Net.Net50,
                MarkupOptions = MarkupOptions.UseFirstDescriptor,
            };
        }
    }
}