// 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.

#nullable disable

using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Testing;
using Microsoft.VisualStudio.Shell.Interop;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
using VerifyCS = Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions.CSharpCodeRefactoringVerifier<Microsoft.CodeAnalysis.CSharp.ConvertIfToSwitch.CSharpConvertIfToSwitchCodeRefactoringProvider>;

namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.CodeActions.ConvertIfToSwitch
{
    public class ConvertIfToSwitchTests
    {
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestUnreachableEndPoint()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 || i == 2 || i == 3)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1:
            case 2:
            case 3:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestReachableEndPoint()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 || i == 2 || i == 3)
            M(i);
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1:
            case 2:
            case 3:
                M(i);
                break;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMissingOnSubsequentBlock()
        {
            var code = @"class C
{
    int M(int i)
    {
        $$if (i == 3) return 0;
        { if (i == 6) return 1; }
        return 2;
    }
}";

            await VerifyCS.VerifyRefactoringAsync(code, code);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestElseBlock_01()
        {
            var source =
@"class C
{
    int {|#0:M|}(int i)
    {
        $$if (i == 3) return 0;
        else { if (i == 6) return 1; }
    }
}";
            var fixedSource =
@"class C
{
    int {|#0:M|}(int i)
    {
        switch (i)
        {
            case 3:
                return 0;
            case 6:
                return 1;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources = { source },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(3,9): error CS0161: 'C.M(int)': not all code paths return a value
                        DiagnosticResult.CompilerError("CS0161").WithLocation(0).WithArguments("C.M(int)"),
                    },
                },
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(3,9): error CS0161: 'C.M(int)': not all code paths return a value
                        DiagnosticResult.CompilerError("CS0161").WithLocation(0).WithArguments("C.M(int)"),
                    },
                },
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestElseBlock_02()
        {
            var source =
@"class C
{
    int M(int i)
    {
        $$if (i == 3)
        {
            return 0;
        }
        else
        {
            if (i == 6) return 1;
            if (i == 7) return 1;
            return 0;
        }
    }
}";
            var fixedSource =
@"class C
{
    int M(int i)
    {
        switch (i)
        {
            case 3:
                return 0;
            case 6:
                return 1;
            case 7:
                return 1;
            default:
                return 0;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMultipleCases_01()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 || 2 == i || i == 3) M(0);
        else if (i == 4 || 5 == i || i == 6) M(1);
        else M(2);
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1:
            case 2:
            case 3:
                M(0);
                break;
            case 4:
            case 5:
            case 6:
                M(1);
                break;
            default:
                M(2);
                break;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMultipleCases_02_CSharp8()
        {
            var source =
@"class C
{
    void M(object o)
    {
        $$if (o is string s && s.Length > 0) M(0);
        else if (o is int i && i > 0) M(1);
        else return;
    }
}";
            var fixedSource =
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case string s when s.Length > 0:
                M(0);
                break;
            case int i when i > 0:
                M(1);
                break;
            default:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp8,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMultipleCases_02_CSharp9()
        {
            var source =
@"class C
{
    void M(object o)
    {
        $$if (o is string s && s.Length > 0) M(0);
        else if (o is int i && i > 0) M(1);
        else return;
    }
}";
            var fixedSource =
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case string s when s.Length > 0:
                M(0);
                break;
            case int i when i > 0:
                M(1);
                break;
            default:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp9,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestExpressionOrder()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (1 == i || i == 2 || 3 == i)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1:
            case 2:
            case 3:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestConstantExpression()
        {
            var source =
@"class C
{
    void M(int i)
    {
        const int A = 1, B = 2, C = 3;
        $$if (A == i || B == i || C == i)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        const int A = 1, B = 2, C = 3;
        switch (i)
        {
            case A:
            case B:
            case C:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMissingOnNonConstantExpression()
        {
            var source =
@"class C
{
    void M(int i)
    {
        int A = 1, B = 2, C = 3;
        $$if (A == i || B == i || C == i)
            return;
    }
}";

            await VerifyCS.VerifyRefactoringAsync(source, source);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMissingOnDifferentOperands()
        {
            var source =
@"class C
{
    void M(int i, int j)
    {
        $$if (i == 5 || 6 == j) {}
    }
}";

            await VerifyCS.VerifyRefactoringAsync(source, source);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMissingOnSingleCase()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 5) {}
    }
}";

            await VerifyCS.VerifyRefactoringAsync(source, source);
        }

        [Theory, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        [CombinatorialData]
        public async Task TestIsExpression(
            [CombinatorialValues(LanguageVersion.CSharp8, LanguageVersion.CSharp9)] LanguageVersion languageVersion)
        {
            var source =
@"class C
{
    void M(object o)
    {
        $$if (o is int || o is string || o is C)
            return;
    }
}";
            var fixedSource = languageVersion switch
            {
                LanguageVersion.CSharp8 =>
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case int _:
            case string _:
            case C _:
                return;
        }
    }
}",
                LanguageVersion.CSharp9 =>
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case int:
            case string:
            case C:
                return;
        }
    }
}",
                _ => throw ExceptionUtilities.Unreachable,
            };

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = languageVersion,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestIsPatternExpression_01()
        {
            await VerifyCS.VerifyRefactoringAsync(
@"class C
{
    void M(object o)
    {
        $$if (o is int i)
                return;
            else if (o is string s)
                return;
    }
}",
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case int i:
                return;
            case string s:
                return;
        }
    }
}");
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestIsPatternExpression_02_CSharp8()
        {
            var source =
@"class C
{
    void M(object o)
    {
        $$if (o is string s && s.Length == 5)
                return;
            else if (o is int i)
                return;
    }
}";
            var fixedSource =
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case string s when s.Length == 5:
                return;
            case int i:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp8,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestIsPatternExpression_02_CSharp9()
        {
            var source =
@"class C
{
    void M(object o)
    {
        $$if (o is string s && s.Length == 5)
                return;
            else if (o is int i)
                return;
    }
}";
            var fixedSource =
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case string s when s.Length == 5:
                return;
            case int i:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp8,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestIsPatternExpression_03()
        {
            await VerifyCS.VerifyRefactoringAsync(
@"class C
{
    void M(object o)
    {
        $$if (o is string s && (s.Length > 5 && s.Length < 10))
                return;
            else if (o is int i)
                return;
    }
}",
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case string s when s.Length > 5 && s.Length < 10:
                return;
            case int i:
                return;
        }
    }
}");
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestIsPatternExpression_04()
        {
            await VerifyCS.VerifyRefactoringAsync(
@"class C
{
    void M(object o)
    {
        $$if (o is string s && s.Length > 5 && s.Length < 10)
                return;
            else if (o is int i)
                return;
    }
}",
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case string s when s.Length > 5 && s.Length < 10:
                return;
            case int i:
                return;
        }
    }
}");
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestComplexExpression_01()
        {
            await VerifyCS.VerifyRefactoringAsync(
@"class C
{
    void M(object o)
    {
        $$if (o is string s && s.Length > 5 &&
                                 s.Length < 10)
            {
                M(o:   0);

            }
            else if (o is int i)
            {
                M(o:   0);
            }
    }
}",
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case string s when s.Length > 5 && s.Length < 10:
                M(o: 0);

                break;
            case int i:
                M(o: 0);
                break;
        }
    }
}");
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMissingIfCaretDoesntIntersectWithTheIfKeyword()
        {
            var source =
@"class C
{
    void M(int i)
    {
        if $$(i == 3) {}
    }
}";

            await VerifyCS.VerifyRefactoringAsync(source, source);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestKeepBlockIfThereIsVariableDeclaration()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 3)
        {
            var x = i;
        }
        else if (i == 4)
        {
        }
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 3:
                {
                    var x = i;
                    break;
                }

            case 4:
                break;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMissingOnBreak_01()
        {
            var source =
@"class C
{
    void M(int i)
    {
        while (true)
        {
            $$if (i == 5) break;
        }
    }
}";

            await VerifyCS.VerifyRefactoringAsync(source, source);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestMissingOnBreak_02()
        {
            var source =
@"class C
{
    void M(int i)
    {
        while (true)
        {
            $$if (i == 5) M({|#0:b|}, i);
            else break;
        }
    }
}";

            await VerifyCS.VerifyRefactoringAsync(
                source,
                // /0/Test0.cs(7,27): error CS0103: The name 'b' does not exist in the current context
                DiagnosticResult.CompilerError("CS0103").WithLocation(0).WithArguments("b"),
                source);
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestNestedBreak()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1)
        {
            while (true)
            {
                break;
            }
        }
        else if (i == 2)
        {
        }
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1:
                while (true)
                {
                    break;
                }
                break;
            case 2:
                break;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestSubsequentIfStatements_01()
        {
            var source =
@"class C
{
    int M(int? i)
    {
        $$if (i == null) return 5;
        if (i == 0) return 6;
        return 7;
    }
}";
            var fixedSource =
@"class C
{
    int M(int? i)
    {
        switch (i)
        {
            case null:
                return 5;
            case 0:
                return 6;
            default:
                return 7;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestSwitchExpression_01()
        {
            var source =
                @"class C
{
    int M(int? i)
    {
        $$if (i == null) return 5;
        if (i == 0) return 6;
        return 7;
    }
}";
            var fixedSource =
@"class C
{
    int M(int? i)
    {
        return i switch
        {
            null => 5,
            0 => 6,
            _ => 7
        };
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionIndex = 1,
                CodeActionEquivalenceKey = "SwitchExpression",
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestSwitchExpression_02()
        {
            var source =
@"class C
{
    int M(int? i)
    {
        $$if (i == null) { return 5; }
        if (i == 0) { return 6; }
        else { return 7; }
    }
}";
            var fixedSource =
@"class C
{
    int M(int? i)
    {
        return i switch
        {
            null => 5,
            0 => 6,
            _ => 7
        };
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionIndex = 1,
                CodeActionEquivalenceKey = "SwitchExpression",
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestSubsequentIfStatements_02()
        {
            var source =
@"class C
{
    int M(int? i)
    {
        $$if (i == null) return 5;
        if (i == 0) {}
        if (i == 1) return 6;
        return 7;
    }
}";
            var fixedSource =
@"class C
{
    int M(int? i)
    {
        switch (i)
        {
            case null:
                return 5;
            case 0:
                break;
        }
        if (i == 1) return 6;
        return 7;
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestSubsequentIfStatements_03()
        {
            var source =
@"class C
{
    int {|#0:M|}(int? i)
    {
        while (true)
        {
            $$if (i == null) return 5; else if (i == 1) return 1;
            if (i == 0) break;
            if (i == 1) return 6;
            return 7;
        }
    }
}";
            var fixedSource =
@"class C
{
    int {|#0:M|}(int? i)
    {
        while (true)
        {
            switch (i)
            {
                case null:
                    return 5;
                case 1:
                    return 1;
            }
            if (i == 0) break;
            if (i == 1) return 6;
            return 7;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources = { source },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(3,9): error CS0161: 'C.M(int?)': not all code paths return a value
                        DiagnosticResult.CompilerError("CS0161").WithLocation(0).WithArguments("C.M(int?)"),
                    },
                },
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(3,9): error CS0161: 'C.M(int?)': not all code paths return a value
                        DiagnosticResult.CompilerError("CS0161").WithLocation(0).WithArguments("C.M(int?)"),
                    },
                },
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestSubsequentIfStatements_04()
        {
            var source =
@"class C
{
    string M(object i)
    {
        $$if (i == null || i as string == """") return null;
        if ((string)i == ""0"") return i as string;
        else return i.ToString();
    }
}";
            var fixedSource =
@"class C
{
    string M(object i)
    {
        switch (i)
        {
            case null:
            case """":
                return null;
            case ""0"":
                return i as string;
            default:
                return i.ToString();
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestSubsequentIfStatements_05()
        {
            var source =
@"class C
{
    int M(int i)
    {
        $$if (i == 10) return 5;
        if (i == 20) return 6;
        if (i == i) return 0;
        return 7;
    }
}";
            var fixedSource =
@"class C
{
    int M(int i)
    {
        switch (i)
        {
            case 10:
                return 5;
            case 20:
                return 6;
        }
        if (i == i) return 0;
        return 7;
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestSubsequentIfStatements_06()
        {
            var source =
@"class C
{
    int M(int i)
    {
        $$if (i == 10)
        {
            return 5;
        }
        else if (i == 20)
        {
            return 6;
        }
        if (i == i) 
        {
            return 0;
        }
        return 7;
    }
}";
            var fixedSource =
@"class C
{
    int M(int i)
    {
        switch (i)
        {
            case 10:
                return 5;
            case 20:
                return 6;
        }
        if (i == i) 
        {
            return 0;
        }
        return 7;
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestSubsequentIfStatements_07()
        {
            var source =
@"class C
{
    int M(int i)
    {
        $$if (i == 5)
        {
            return 4;
        }
        else if (i == 1)
        {
            return 1;
        }

        if (i == 10)
        {
            return 5;
        }
        else if (i == i)
        {
            return 6;
        }
        else
        {
            return 0;
        }
        return 7;
    }
}";
            var fixedSource =
@"class C
{
    int M(int i)
    {
        switch (i)
        {
            case 5:
                return 4;
            case 1:
                return 1;
        }

        if (i == 10)
        {
            return 5;
        }
        else if (i == i)
        {
            return 6;
        }
        else
        {
            return 0;
        }
        return 7;
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21109, "https://github.com/dotnet/roslyn/issues/21109")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestTrivia1()
        {
            var source =
@"class C
{
    int {|#0:M|}(int x, int z)
    {
#if TRUE
        {|#1:Console|}.WriteLine();
#endif

        $$if (x == 1)
        {
            {|#2:Console|}.WriteLine(x + z);
        }
        else if (x == 2)
        {
            {|#3:Console|}.WriteLine(x + z);
        }
    }
}";
            var fixedSource =
@"class C
{
    int {|#0:M|}(int x, int z)
    {
#if TRUE
        {|#1:Console|}.WriteLine();
#endif

        switch (x)
        {
            case 1:
                {|#2:Console|}.WriteLine(x + z);
                break;
            case 2:
                {|#3:Console|}.WriteLine(x + z);
                break;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestState =
                {
                    Sources = { source },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(3,9): error CS0161: 'C.M(int, int)': not all code paths return a value
                        DiagnosticResult.CompilerError("CS0161").WithLocation(0).WithArguments("C.M(int, int)"),
                        // /0/Test0.cs(6,9): error CS0103: The name 'Console' does not exist in the current context
                        DiagnosticResult.CompilerError("CS0103").WithLocation(1).WithArguments("Console"),
                        // /0/Test0.cs(11,13): error CS0103: The name 'Console' does not exist in the current context
                        DiagnosticResult.CompilerError("CS0103").WithLocation(2).WithArguments("Console"),
                        // /0/Test0.cs(15,13): error CS0103: The name 'Console' does not exist in the current context
                        DiagnosticResult.CompilerError("CS0103").WithLocation(3).WithArguments("Console"),
                    },
                },
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(3,9): error CS0161: 'C.M(int, int)': not all code paths return a value
                        DiagnosticResult.CompilerError("CS0161").WithLocation(0).WithArguments("C.M(int, int)"),
                        // /0/Test0.cs(6,9): error CS0103: The name 'Console' does not exist in the current context
                        DiagnosticResult.CompilerError("CS0103").WithLocation(1).WithArguments("Console"),
                        // /0/Test0.cs(11,13): error CS0103: The name 'Console' does not exist in the current context
                        DiagnosticResult.CompilerError("CS0103").WithLocation(2).WithArguments("Console"),
                        // /0/Test0.cs(15,13): error CS0103: The name 'Console' does not exist in the current context
                        DiagnosticResult.CompilerError("CS0103").WithLocation(3).WithArguments("Console"),
                    },
                },
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21101, "https://github.com/dotnet/roslyn/issues/21101")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestTrivia2()
        {
            var source =
@"class C
{
    int M(int i, string[] args)
    {
        $$if (/* t0 */args.Length /* t1*/ == /* t2 */ 2)
            return /* t3 */ 0 /* t4 */; /* t5 */
        else /* t6 */
            return /* t7 */ 3 /* t8 */;
    }
}";
            var fixedSource =
@"class C
{
    int M(int i, string[] args)
    {
        switch (/* t0 */args.Length /* t1*/ )
        {
            case 2:
                return /* t3 */ 0 /* t4 */; /* t5 */
            default:
                return /* t7 */ 3 /* t8 */;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd1_CSharp8()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && i == 2)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp8,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd1_CSharp9()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && i == 2)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case {|#0:1 and 2|}:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(7,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                        DiagnosticResult.CompilerError("CS8120").WithLocation(0),
                    },
                },
                LanguageVersion = LanguageVersion.CSharp9,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd2_CSharp8()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && i == 2 && i == 3)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp8,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd2_CSharp9()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && i == 2 && i == 3)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case {|#0:1 and 2 and 3|}:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(7,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                        DiagnosticResult.CompilerError("CS8120").WithLocation(0),
                    },
                },
                LanguageVersion = LanguageVersion.CSharp9,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd3_CSharp8()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && i == 2 && (i == 3))
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp8,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd3_CSharp9()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && i == 2 && (i == 3))
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case {|#0:1 and 2 and 3|}:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(7,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                        DiagnosticResult.CompilerError("CS8120").WithLocation(0),
                    },
                },
                LanguageVersion = LanguageVersion.CSharp9,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd4()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && (i == 2) && i == 3)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp8,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd4_CSharp9()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && (i == 2) && i == 3)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case {|#0:1 and 2 and 3|}:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(7,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                        DiagnosticResult.CompilerError("CS8120").WithLocation(0),
                    },
                },
                LanguageVersion = LanguageVersion.CSharp9,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd5()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && (i == 2) && (i == 3))
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd6()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if ((i == 1) && i == 2 && i == 3)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd7()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if ((i == 1) && i == 2 && (i == 3))
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd8()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if ((i == 1) && (i == 2) && i == 3)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd9()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if ((i == 1) && (i == 2) && (i == 3))
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd10()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 1 && (i == 2 && i == 3))
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd11()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if ((i == 1 && i == 2) && i == 3)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd12()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (((i == 1) && i == 2) && i == 3)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd13()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if ((i == 1 && (i == 2)) && i == 3)
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd14()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if ((i == 1 && (i == 2)) && (i == 3))
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd15()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if ((i == 1) && ((i == 2) && i == 3))
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(21360, "https://github.com/dotnet/roslyn/issues/21360")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestCompoundLogicalAnd16()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if ((i == 1) && (i == 2 && (i == 3)))
            return;
        else if (i == 10)
            return;
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 1 when i == 2 && i == 3:
                return;
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(37035, "https://github.com/dotnet/roslyn/issues/37035")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestComplexExpression_02()
        {
            await VerifyCS.VerifyRefactoringAsync(
@"class C
{
    void M(object o)
    {
        $$if (o is string text &&
            int.TryParse(text, out var n) &&
            n < 5 && n > -5)
        {
        }
        else
        {
        }
    }
}",
@"class C
{
    void M(object o)
    {
        switch (o)
        {
            case string text when int.TryParse(text, out var n) && n < 5 && n > -5:
                break;
            default:
                break;
        }
    }
}");
        }

        [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestRange_CSharp8()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (5 >= i && 1 <= i)
        {
            return;
        }
        else if (7 >= i && 6 <= i)
        {
            return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = source,
                LanguageVersion = LanguageVersion.CSharp8,
            }.RunAsync();
        }

        [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestRange_CSharp9()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (5 >= i && 1 <= i)
        {
            return;
        }
        else if (7 >= i && 6 <= i)
        {
            return;
        }
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case <= 5 and >= 1:
                return;
            case <= 7 and >= 6:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp9,
            }.RunAsync();
        }

        [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestComparison_CSharp8()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (5 >= i || 1 <= i)
        {
            return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = source,
                LanguageVersion = LanguageVersion.CSharp8,
            }.RunAsync();
        }

        [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestComparison_CSharp9()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (5 >= i || 1 <= i)
        {
            return;
        }
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case <= 5:
            case >= 1:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp9,
            }.RunAsync();
        }

        [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestComparison_SwitchExpression_CSharp9()
        {
            var source =
@"class C
{
    int M(int i)
    {
        $$if (5 >= i || 1 <= i)
        {
            return 1;
        }
        else
        {
            return 2;
        }
    }
}";
            var fixedSource =
@"class C
{
    int M(int i)
    {
        return i switch
        {
            <= 5 or >= 1 => 1,
            {|#0:_|} => 2
        };
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(8,13): error CS8510: The pattern is unreachable. It has already been handled by a previous arm of the switch expression or it is impossible to match.
                        DiagnosticResult.CompilerError("CS8510").WithLocation(0),
                    },
                },
                LanguageVersion = LanguageVersion.CSharp9,
                CodeActionIndex = 1,
                CodeActionEquivalenceKey = "SwitchExpression",
            }.RunAsync();
        }

        [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestComplexIf_CSharp8()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i < 10 || 20 < i || (i >= 30 && 40 >= i) || i == 50)
        {
            return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = source,
                LanguageVersion = LanguageVersion.CSharp8,
            }.RunAsync();
        }

        [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestComplexIf_CSharp9()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i < 10 || 20 < i || (i >= 30 && 40 >= i) || i == 50)
        {
            return;
        }
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case < 10:
            case > 20:
            case {|#0:>= 30 and <= 40|}:
            case {|#1:50|}:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedState =
                {
                    Sources = { fixedSource },
                    ExpectedDiagnostics =
                    {
                        // /0/Test0.cs(9,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                        DiagnosticResult.CompilerError("CS8120").WithLocation(0),
                        // /0/Test0.cs(10,18): error CS8120: The switch case is unreachable. It has already been handled by a previous case or it is impossible to match.
                        DiagnosticResult.CompilerError("CS8120").WithLocation(1),
                    },
                },
                LanguageVersion = LanguageVersion.CSharp9,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(42368, "https://github.com/dotnet/roslyn/issues/42368")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestComplexIf_Precedence_CSharp9()
        {
            var source =
@"class C
{
    void M(int i)
    {
        $$if (i == 0 || i is < 10 or > 20 && i is >= 30 or <= 40)
        {
            return;
        }
    }
}";
            var fixedSource =
@"class C
{
    void M(int i)
    {
        switch (i)
        {
            case 0:
            case (< 10 or > 20) and (>= 30 or <= 40):
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp9,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestInequality()
        {
            var source =
@"class C
{
    void M(int i)
    {
        [||]if ((i > 123 && i < 456) && i != 0 || i == 10)
        {
            return;
        }
    }
}";

            var fixedSource =
 @"class C
{
    void M(int i)
    {
        switch (i)
        {
            case > 123 and < 456 when i != 0:
            case 10:
                return;
        }
    }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp9,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }

        [WorkItem(44278, "https://github.com/dotnet/roslyn/issues/44278")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task TestTopLevelStatement()
        {
            var source = @"
var e = new ET1();

[||]if (e == ET1.A)
{
}
else if (e == ET1.C)
{
}

enum ET1
{
    A,
    B,
    C,
}";

            var fixedSource = @"
var e = new ET1();

switch (e)
{
    case ET1.A:
        break;
    case ET1.C:
        break;
}

enum ET1
{
    A,
    B,
    C,
}";

            var test = new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                LanguageVersion = LanguageVersion.CSharp9,
                CodeActionValidationMode = CodeActionValidationMode.None,
            };

            test.ExpectedDiagnostics.Add(
                // error CS8805: Program using top-level statements must be an executable.
                DiagnosticResult.CompilerError("CS8805"));

            await test.RunAsync();
        }

        [WorkItem(46863, "https://github.com/dotnet/roslyn/issues/46863")]
        [Fact, Trait(Traits.Feature, Traits.Features.CodeActionsConvertIfToSwitch)]
        public async Task CommentsAtTheEndOfBlocksShouldBePlacedBeforeBreakStatements()
        {
            var source = @"
class C
{
    void M(int p)
    {
        [||]if (p == 1)
        {
            DoA();
            // Comment about why A doesn't need something here
        }
        else if (p == 2)
        {
            DoB();
            // Comment about why B doesn't need something here
        }
    }

    void DoA() { }
    void DoB() { }
}";

            var fixedSource = @"
class C
{
    void M(int p)
    {
        switch (p)
        {
            case 1:
                DoA();
                // Comment about why A doesn't need something here
                break;
            case 2:
                DoB();
                // Comment about why B doesn't need something here
                break;
        }
    }

    void DoA() { }
    void DoB() { }
}";

            await new VerifyCS.Test
            {
                TestCode = source,
                FixedCode = fixedSource,
                CodeActionValidationMode = CodeActionValidationMode.None,
            }.RunAsync();
        }
    }
}
