File: ConvertCast\ConvertDirectCastToTryCastTests.cs
Web Access
Project: src\src\Features\CSharpTest\Microsoft.CodeAnalysis.CSharp.Features.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Features.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp.ConvertCast;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Testing;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.ConvertConversionOperators;
 
using VerifyCS = CSharpCodeRefactoringVerifier<CSharpConvertDirectCastToTryCastCodeRefactoringProvider>;
 
[UseExportProvider]
[Trait(Traits.Feature, Traits.Features.ConvertCast)]
public class ConvertDirectCastToTryCastTests
{
    [Fact]
    public async Task ConvertFromExplicitToAs()
    {
        const string InitialMarkup = """
            class Program
            {
                public static void Main()
                {
                    var x = ([||]object)1;
                }
            }
            """;
        const string ExpectedMarkup = """
            class Program
            {
                public static void Main()
                {
                    var x = 1 as object;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = InitialMarkup,
            FixedCode = ExpectedMarkup,
            CodeActionValidationMode = CodeActionValidationMode.Full,
        }.RunAsync();
    }
 
    [Theory]
    [InlineData("dynamic")]
    [InlineData("IComparable")]
    [InlineData("Action")]
    [InlineData("int[]")]
    [InlineData("List<int>")]
    public async Task ConvertFromExplicitToAsSpecialTypes(string targetType)
    {
        var initialMarkup = @$"
using System;
using System.Collections.Generic;
 
class Program
{{
    public static void Main()
    {{
        var o = new object();
        var x = ([||]{targetType})o;
    }}
}}";
        var expectedMarkup = @$"
using System;
using System.Collections.Generic;
 
class Program
{{
    public static void Main()
    {{
        var o = new object();
        var x = o as {targetType};
    }}
}}";
 
        await new VerifyCS.Test
        {
            TestCode = initialMarkup,
            FixedCode = expectedMarkup,
            CodeActionValidationMode = CodeActionValidationMode.Full,
        }.RunAsync();
    }
 
    [Fact]
    public async Task ConvertFromExplicitToAs_ValueType()
    {
        const string InitialMarkup = """
            class Program
            {
                public static void Main()
                {
                    var x = ([||]byte)1;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = InitialMarkup,
            OffersEmptyRefactoring = false,
            CodeActionValidationMode = CodeActionValidationMode.None,
        }.RunAsync();
    }
 
    [Fact]
    public async Task ConvertFromExplicitToAs_ValueTypeConstraint()
    {
        const string InitialMarkup = """
            public class C
            {
                public void M<T>() where T: struct
                {
                    var o = new object();
                    var t = (T[||])o;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = InitialMarkup,
            OffersEmptyRefactoring = false,
            CodeActionValidationMode = CodeActionValidationMode.None,
        }.RunAsync();
    }
 
    [Fact]
    public async Task ConvertFromExplicitToAs_Unconstraint()
    {
        const string InitialMarkup = """
            public class C
            {
                public void M<T>()
                {
                    var o = new object();
                    var t = (T[||])o;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = InitialMarkup,
            OffersEmptyRefactoring = false,
            CodeActionValidationMode = CodeActionValidationMode.None,
        }.RunAsync();
    }
 
    [Fact]
    public async Task ConvertFromExplicitToAs_ClassConstraint()
    {
        const string InitialMarkup = """
            public class C
            {
                public void M<T>() where T: class
                {
                    var o = new object();
                    var t = (T[||])o;
                }
            }
            """;
        const string FixedCode = """
            public class C
            {
                public void M<T>() where T: class
                {
                    var o = new object();
                    var t = o as T;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = InitialMarkup,
            FixedCode = FixedCode,
            CodeActionValidationMode = CodeActionValidationMode.Full,
        }.RunAsync();
    }
 
    [Theory]
    [InlineData("class", true)]
    [InlineData("interface", false)]
    public async Task ConvertFromExplicitToAs_ConcreteClassOrInterfaceConstraint(string targetTypeKind, bool shouldBeFixed)
    {
        var initialMarkup = @$"
public {targetTypeKind} Target {{ }}
 
public class C
{{
    public void M<T>() where T: Target
    {{
        var o = new object();
        var t = (T[||])o;
    }}
}}
";
        var fixedCode = @$"
public {targetTypeKind} Target {{ }}
 
public class C
{{
    public void M<T>() where T: Target
    {{
        var o = new object();
        var t = o as T;
    }}
}}
";
        await new VerifyCS.Test
        {
            TestCode = initialMarkup,
            FixedCode = shouldBeFixed ? fixedCode : initialMarkup,
            OffersEmptyRefactoring = false,
            CodeActionValidationMode = CodeActionValidationMode.Full,
        }.RunAsync();
    }
 
    [Fact]
    public async Task ConvertFromExplicitToAs_NestedTypeParameters()
    {
        var initialMarkup = """
            public class Target { }
 
            public class C
            {
                public void M<T, U>()
                    where T: Target
                    where U: T
                {
                    var o = new object();
                    var u = (U[||])o;
                }
            }
            """;
        var fixedCode = """
            public class Target { }
 
            public class C
            {
                public void M<T, U>()
                    where T: Target
                    where U: T
                {
                    var o = new object();
                    var u = o as U;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = initialMarkup,
            FixedCode = fixedCode,
            OffersEmptyRefactoring = false,
            CodeActionValidationMode = CodeActionValidationMode.Full,
        }.RunAsync();
    }
 
    [Fact]
    public async Task ConvertFromExplicitToAs_MissingType()
    {
        const string InitialMarkup = """
            public class C
            {
                public void M()
                {
                    var o = new object();
                    var t = ({|#0:MissingType|})$$o;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestState = {
                Sources = { InitialMarkup },
                // /0/Test0.cs(7,18): error CS0246: Type or namespace "MissingType" not found.
                ExpectedDiagnostics = { DiagnosticResult.CompilerError("CS0246").WithLocation(0).WithArguments("MissingType") }
            },
            FixedCode = InitialMarkup,
            OffersEmptyRefactoring = false,
            CodeActionValidationMode = CodeActionValidationMode.None,
        }.RunAsync();
    }
    [Theory]
    [InlineData("(C$$)((object)1)",
                "((object)1) as C")]
    [InlineData("(C)((object$$)1)",
                "(C)(1 as object)")]
    public async Task ConvertFromExplicitToAs_Nested(string cast, string asExpression)
    {
        var initialMarkup = @$"
class C {{ }}
 
class Program
{{
    public static void Main()
    {{
        var x = {cast};
    }}
}}
";
        var expectedMarkup = @$"
class C {{ }}
 
class Program
{{
    public static void Main()
    {{
        var x = {asExpression};
    }}
}}
";
        await new VerifyCS.Test
        {
            TestCode = initialMarkup,
            FixedCode = expectedMarkup,
            CodeActionValidationMode = CodeActionValidationMode.Full,
        }.RunAsync();
 
    }
 
    [Theory]
    [InlineData("/* Leading */ (obj$$ect)1",
                "/* Leading */ 1 as object")]
    [InlineData("(obj$$ect)1 /* Trailing */",
                "1 as object /* Trailing */")]
    [InlineData("(obj$$ect)1; // Trailing",
                "1 as object; // Trailing")]
    [InlineData("(/* Middle1 */ obj$$ect)1",
                """
                1 as
                /* Middle1 */ object
                """)]
    [InlineData("(obj$$ect /* Middle2 */ )1",
                "1 as object /* Middle2 */ ")]
    [InlineData("(obj$$ect) /* Middle3 */ 1",
                "/* Middle3 */ 1 as object")]
    [InlineData("/* Leading */ (/* Middle1 */ obj$$ect /* Middle2 */ ) /* Middle3 */ 1 /* Trailing */",
                """
                /* Leading */ /* Middle3 */ 1 as
                /* Middle1 */ object /* Middle2 */  /* Trailing */
                """)]
    [InlineData("""
        ($$
        object
        )
        1
        """, """
 
        1 as
        object
        """)]
    public async Task ConvertFromExplicitToAs_Trivia(string cast, string asExpression)
    {
        var initialMarkup = @$"
class Program
{{
    public static void Main()
    {{
        var x = {cast};
    }}
}}
";
        var expectedMarkup = @$"
class Program
{{
    public static void Main()
    {{
        var x = {asExpression};
    }}
}}
";
        await new VerifyCS.Test
        {
            TestCode = initialMarkup,
            FixedCode = expectedMarkup,
            CodeActionValidationMode = CodeActionValidationMode.SemanticStructure,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64052")]
    public async Task ConvertFromExplicitToAs_NullableReferenceType_NullableEnable()
    {
        var initialMarkup = """
            #nullable enable
 
            class Program
            {
                public static void Main()
                {
                    var x = ([||]string?)null;
                }
            }
            """;
        var expectedMarkup = """
            #nullable enable
 
            class Program
            {
                public static void Main()
                {
                    var x = null as string;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = initialMarkup,
            FixedCode = expectedMarkup,
            CodeActionValidationMode = CodeActionValidationMode.Full,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64052")]
    public async Task ConvertFromExplicitToAs_NullableReferenceType_NullableDisable()
    {
        var initialMarkup = """
            #nullable disable
 
            class Program
            {
                public static void Main()
                {
                    var x = ([||]string?)null;
                }
            }
            """;
        var expectedMarkup = """
            #nullable disable
 
            class Program
            {
                public static void Main()
                {
                    var x = null as string;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = initialMarkup,
            FixedCode = expectedMarkup,
            CompilerDiagnostics = CompilerDiagnostics.None, // Suppress compiler warning about nullable string in non-nullable context
            CodeActionValidationMode = CodeActionValidationMode.Full,
        }.RunAsync();
    }
 
    [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/64466")]
    public async Task ConvertFromExplicitToAs_NullableValueType()
    {
        const string InitialMarkup = """
            class Program
            {
                public static void Main()
                {
                    var x = ([||]byte?)null;
                }
            }
            """;
        const string FixedCode = """
            class Program
            {
                public static void Main()
                {
                    var x = null as byte?;
                }
            }
            """;
        await new VerifyCS.Test
        {
            TestCode = InitialMarkup,
            FixedCode = FixedCode,
            CodeActionValidationMode = CodeActionValidationMode.Full,
        }.RunAsync();
    }
}