File: Recommendations\WhenKeywordRecommenderTests.cs
Web Access
Project: src\src\EditorFeatures\CSharpTest2\Microsoft.CodeAnalysis.CSharp.EditorFeatures2.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures2.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.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Recommendations
{
    [Trait(Traits.Feature, Traits.Features.KeywordRecommending)]
    public class WhenKeywordRecommenderTests : KeywordRecommenderTests
    {
        [Fact]
        public async Task TestForCatchClause_AfterCatch()
        {
            await VerifyKeywordAsync(AddInsideMethod(
@"try {} catch $$"));
        }
 
        [Fact]
        public async Task TestForCatchClause_AfterCatchDeclaration1()
        {
            await VerifyKeywordAsync(AddInsideMethod(
@"try {} catch (Exception) $$"));
        }
 
        [Fact]
        public async Task TestForCatchClause_AfterCatchDeclaration2()
        {
            await VerifyKeywordAsync(AddInsideMethod(
@"try {} catch (Exception e) $$"));
        }
 
        [Fact]
        public async Task TestForCatchClause_AfterCatchDeclarationEmpty()
        {
            await VerifyKeywordAsync(AddInsideMethod(
@"try {} catch () $$"));
        }
 
        [Fact]
        public async Task TestForCatchClause_NotAfterTryBlock()
        {
            await VerifyAbsenceAsync(AddInsideMethod(
@"try {} $$"));
        }
 
        [Fact]
        public async Task TestForCatchClause_NotAfterFilter1()
        {
            await VerifyAbsenceAsync(AddInsideMethod(
@"try {} catch (Exception e) when $$"));
        }
 
        [Fact]
        public async Task TestForCatchClause_NotAfterFilter2()
        {
            await VerifyAbsenceAsync(AddInsideMethod(
@"try {} catch (Exception e) when ($$"));
        }
 
        [Fact]
        public async Task TestForCatchClause_NotAfterFilter3()
        {
            await VerifyAbsenceAsync(AddInsideMethod(
@"try {} catch (Exception e) when (true) $$"));
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/24113")]
        public async Task TestForSwitchCase_AfterDeclarationPattern()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (1) { case int i $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_AfterDeclarationPattern_BeforeBreak()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (1) { case int i $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_AfterDeclarationPattern_BeforeWhen()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (1) { case int i $$ when }"));
 
        [Theory, WorkItem("https://github.com/dotnet/roslyn/issues/25084")]
        [InlineData("int.MinValue")]
        [InlineData("1")]
        [InlineData("1 + 1")]
        [InlineData("true ? 1 : 1")]
        [InlineData("(1 + )")]
        public async Task TestForSwitchCase_AfterExpression(string expression)
            => await VerifyKeywordAsync(AddInsideMethod($@"switch (1) {{ case {expression} $$ }}"));
 
        [Theory]
        [InlineData("int.MinValue")]
        [InlineData("1")]
        [InlineData("1 + 1")]
        [InlineData("true ? 1 : 1")]
        [InlineData("(1 + )")]
        public async Task TestForSwitchCase_AfterExpression_BeforeBreak(string expression)
            => await VerifyKeywordAsync(AddInsideMethod($@"switch (1) {{ case {expression} $$ break; }}"));
 
        [Theory]
        [InlineData("int.MinValue")]
        [InlineData("1")]
        [InlineData("1 + 1")]
        [InlineData("true ? 1 : 1")]
        [InlineData("(1 + )")]
        public async Task TestForSwitchCase_AfterExpression_BeforeWhen(string expression)
            => await VerifyKeywordAsync(AddInsideMethod($@"switch (1) {{ case {expression} $$ when }}"));
 
        [Theory]
        [InlineData("int.")]
        [InlineData("1 +")]
        [InlineData("true ?")]
        [InlineData("true ? 1")]
        [InlineData("true ? 1 :")]
        [InlineData("(1")]
        [InlineData("(1 + 1")]
        public async Task TestForSwitchCase_NotAfterIncompleteExpression(string expression)
            => await VerifyAbsenceAsync(AddInsideMethod($@"switch (1) {{ case {expression} $$ }}"));
 
        [Theory]
        [InlineData("int.")]
        [InlineData("1 +")]
        [InlineData("true ?")]
        [InlineData("true ? 1")]
        [InlineData("true ? 1 :")]
        [InlineData("(1")]
        [InlineData("(1 + 1")]
        public async Task TestForSwitchCase_NotAfterIncompleteExpression_BeforeBreak(string expression)
            => await VerifyAbsenceAsync(AddInsideMethod($@"switch (1) {{ case {expression} $$ break; }}"));
 
        [Theory]
        [InlineData("int.")]
        [InlineData("1 +")]
        [InlineData("true ?")]
        [InlineData("true ? 1")]
        [InlineData("true ? 1 :")]
        [InlineData("(1")]
        [InlineData("(1 + 1")]
        public async Task TestForSwitchCase_NotAfterIncompleteExpression_BeforeWhen(string expression)
            => await VerifyAbsenceAsync(AddInsideMethod($@"switch (1) {{ case {expression} $$ when }}"));
 
        [Fact]
        public async Task TestForSwitchCase_NotInsideExpression()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case (1 + 1 $$) }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotInsideExpression_BeforeBreak()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case (1 + 1 $$) break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotInsideExpression_BeforeWhen()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case (1 + 1 $$) when }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotAfterCase()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotAfterCase_BeforeBreak()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotAfterCase_BeforeWhen()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case $$ when }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotAfterDefault()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { default $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotAfterDefault_BeforeBreak()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { default $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotAfterWhen()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case 1 when $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotAfterWhen_BeforeBreak()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case 1 when $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotAfterColon()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case 1: $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotAfterColon_BeforeBreak()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { case 1: $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_NotInEmptySwitchStatement()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (1) { $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterPredefinedType()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (new object()) { case int $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterPredefinedType_BeforeBreak()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (new object()) { case int $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterPredefinedType_BeforeWhen()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (new object()) { case int $$ when }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterGenericType()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (new object()) { case Dictionary<string, int> $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterGenericType_BeforeBreak()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (new object()) { case Dictionary<string, int> $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterGenericType_BeforeWhen()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (new object()) { case Dictionary<string, int> $$ when }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterCustomType()
            => await VerifyKeywordAsync("""
                class SyntaxNode { }
                class C
                {
                    void M() { switch (new object()) { case SyntaxNode $$ } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterCustomType_BeforeBreak()
            => await VerifyKeywordAsync("""
                class SyntaxNode { }
                class C
                {
                    void M() { switch (new object()) { case SyntaxNode $$ break; } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterCustomType_BeforeWhen()
            => await VerifyKeywordAsync("""
                class SyntaxNode { }
                class C
                {
                    void M() { switch (new object()) { case SyntaxNode $$ when } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterTypeAlias()
            => await VerifyKeywordAsync("""
                using Type = System.String;
                class C
                {
                    void M() { switch (new object()) { case Type $$ } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterTypeAlias_BeforeBreak()
            => await VerifyKeywordAsync("""
                using Type = System.String;
                class C
                {
                    void M() { switch (new object()) { case Type $$ break; } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterTypeAlias_BeforeWhen()
            => await VerifyKeywordAsync("""
                using Type = System.String;
                class C
                {
                    void M() { switch (new object()) { case Type $$ when } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterOverloadedTypeName()
    => await VerifyKeywordAsync("""
        class ValueTuple { }
        class ValueTuple<T> { }
        class C
        {
            void M() { switch (new object()) { case ValueTuple $$ } }
        }
        """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterOverloadedTypeName_BeforeBreak()
            => await VerifyKeywordAsync("""
                class ValueTuple { }
                class ValueTuple<T> { }
                class C
                {
                    void M() { switch (new object()) { case ValueTuple $$ break; } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterOverloadedTypeName_BeforeWhen()
            => await VerifyKeywordAsync("""
                class ValueTuple { }
                class ValueTuple<T> { }
                class C
                {
                    void M() { switch (new object()) { case ValueTuple $$ when } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterColorColor()
            => await VerifyKeywordAsync("""
                class Color { }
                class C
                {
                    const Color Color = null;
                    void M() { switch (new object()) { case Color $$ } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterColorColor_BeforeBreak()
            => await VerifyKeywordAsync("""
                class Color { }
                class C
                {
                    const Color Color = null;
                    void M() { switch (new object()) { case Color $$ break; } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterColorColor_BeforeWhen()
            => await VerifyKeywordAsync("""
                class Color { }
                class C
                {
                    const Color Color = null;
                    void M() { switch (new object()) { case Color $$ when } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterOverloadedTypeNameColorColor()
    => await VerifyKeywordAsync("""
        class Color<T> { }
        class Color { }
        class C
        {
            const Color Color = null;
            void M() { switch (new object()) { case Color $$ } }
        }
        """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterOverloadedTypeNameColorColor_BeforeBreak()
            => await VerifyKeywordAsync("""
                class Color<T> { }
                class Color { }
                class C
                {
                    const Color Color = null;
                    void M() { switch (new object()) { case Color $$ break; } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterOverloadedTypeNameColorColor_BeforeWhen()
            => await VerifyKeywordAsync("""
                class Color<T> { }
                class Color { }
                class C
                {
                    const Color Color = null;
                    void M() { switch (new object()) { case Color $$ when } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterLocalConstant()
            => await VerifyKeywordAsync(AddInsideMethod(@"const object c = null; switch (new object()) { case c $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterLocalConstant_BeforeBreak()
            => await VerifyKeywordAsync(AddInsideMethod(@"const object c = null; switch (new object()) { case c $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterLocalConstant_BeforeWhen()
            => await VerifyKeywordAsync(AddInsideMethod(@"const object c = null; switch (new object()) { case c $$ when }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterUnknownName()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (new object()) { case unknown $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterUnknownName_BeforeBreak()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (new object()) { case unknown $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterUnknownName_BeforeWhen()
            => await VerifyKeywordAsync(AddInsideMethod(@"switch (new object()) { case unknown $$ when }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterVar()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (new object()) { case var $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterVar_BeforeBreak()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (new object()) { case var $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterVar_BeforeWhen()
            => await VerifyAbsenceAsync(AddInsideMethod(@"switch (new object()) { case var $$ when }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterClassVar()
            => await VerifyAbsenceAsync("""
                class var { }
                class C
                {
                    void M() { switch (new object()) { case var $$ } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterClassVar_BeforeBreak()
            => await VerifyAbsenceAsync("""
                class var { }
                class C
                {
                    void M() { switch (new object()) { case var $$ break; } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterClassVar_BeforeWhen()
            => await VerifyAbsenceAsync("""
                class var { }
                class C
                {
                    void M() { switch (new object()) { case var $$ when } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterTypeAliasVar()
        {
            await VerifyAbsenceAsync("""
                using var = System.String;
                class C
                {
                    void M() { switch (new object()) { case var $$ } }
                }
                """);
        }
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterTypeAliasVar_BeforeBreak()
        {
            await VerifyAbsenceAsync("""
                using var = System.String;
                class C
                {
                    void M() { switch (new object()) { case var $$ break; } }
                }
                """);
        }
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_NotAfterTypeAliasVar_BeforeWhen()
        {
            await VerifyAbsenceAsync("""
                using var = System.String;
                class C
                {
                    void M() { switch (new object()) { case var $$ when } }
                }
                """);
        }
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterLocalConstantVar()
            => await VerifyAbsenceAsync(AddInsideMethod(@"const object var = null; switch (new object()) { case var $$ }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterLocalConstantVar_BeforeBreak()
            => await VerifyAbsenceAsync(AddInsideMethod(@"const object var = null; switch (new object()) { case var $$ break; }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterLocalConstantVar_BeforeWhen()
            => await VerifyAbsenceAsync(AddInsideMethod(@"const object var = null; switch (new object()) { case var $$ when }"));
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterClassAndLocalConstantVar()
            => await VerifyAbsenceAsync("""
                class var { }
                class C
                {
                    void M() { const object var = null; switch (new object()) { case var $$ } }
                }
                """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterClassAndLocalConstantVar_BeforeBreak()
    => await VerifyAbsenceAsync("""
        class var { }
        class C
        {
            void M() { const object var = null; switch (new object()) { case var $$ break; } }
        }
        """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterClassAndLocalConstantVar_BeforeWhen()
    => await VerifyAbsenceAsync("""
        class var { }
        class C
        {
            void M() { const object var = null; switch (new object()) { case var $$ when } }
        }
        """);
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterTypeAliasAndFieldConstantVar()
        {
            await VerifyAbsenceAsync("""
                using var = System.String;
                class C
                {
                    const object var = null;
                    void M() { switch (new object()) { case var $$ } }
                }
                """);
        }
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterTypeAliasAndFieldConstantVar_BeforeBreak()
        {
            await VerifyAbsenceAsync("""
                using var = System.String;
                class C
                {
                    const object var = null;
                    void M() { switch (new object()) { case var $$ break; } }
                }
                """);
        }
 
        [Fact]
        public async Task TestForSwitchCase_SemanticCheck_AfterTypeAliasAndFieldConstantVar_BeforeWhen()
        {
            await VerifyAbsenceAsync("""
                using var = System.String;
                class C
                {
                    const object var = null;
                    void M() { switch (new object()) { case var $$ when } }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44480")]
        public async Task TestAfterSwitchExpressionPattern1()
        {
            await VerifyKeywordAsync("""
                using var = System.String;
                class C
                {
                    void M(int i)
                    {
                        _ = i switch
                        {
                            < 0 $$ => 1,
                        };
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44480")]
        public async Task TestAfterSwitchExpressionPattern2()
        {
            await VerifyKeywordAsync("""
                using var = System.String;
                class C
                {
                    void M(int i)
                    {
                        _ = i switch
                        {
                            4 $$ => 1,
                        };
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44480")]
        public async Task TestAfterSwitchExpressionPattern3()
        {
            await VerifyKeywordAsync("""
                using var = System.String;
                class C
                {
                    void M(int i)
                    {
                        _ = i switch
                        {
                            int $$ => 1,
                        };
                    }
                }
                """);
        }
 
        [Fact, WorkItem("https://github.com/dotnet/roslyn/issues/44480")]
        public async Task TestAfterSwitchExpressionPattern4()
        {
            await VerifyKeywordAsync("""
                using var = System.String;
                class C
                {
                    void M(int i)
                    {
                        _ = i switch
                        {
                            int $$ or 1 => 1,
                        };
                    }
                }
                """);
        }
    }
}