File: src\Analyzers\CSharp\Tests\NewLines\ConsecutiveStatementPlacement\ConsecutiveStatementPlacementTests.cs
Web Access
Project: src\src\CodeStyle\CSharp\Tests\Microsoft.CodeAnalysis.CSharp.CodeStyle.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.CodeStyle.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.CodeStyle;
using Microsoft.CodeAnalysis.CSharp.NewLines.ConsecutiveStatementPlacement;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.NewLines.ConsecutiveStatementPlacement;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.NewLines.ConsecutiveStatementPlacement;
 
using Verify = CSharpCodeFixVerifier<
    CSharpConsecutiveStatementPlacementDiagnosticAnalyzer,
    ConsecutiveStatementPlacementCodeFixProvider>;
 
public class ConsecutiveStatementPlacementTests
{
    [Fact]
    public async Task TestNotAfterPropertyBlock()
    {
        var code =
            """
            class C
            {
                int X { get; }
                int Y { get; }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotAfterMethodBlock()
    {
        var code =
            """
            class C
            {
                void X() { }
                void Y() { }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotAfterStatementsOnSingleLine()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true) { } return;
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotAfterStatementsOnSingleLineWithComment()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true) { }/*x*/return;
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotAfterStatementsOnMultipleLinesWithCommentBetween1()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
                    /*x*/ return;
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotAfterStatementsOnMultipleLinesWithCommentBetween2()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
                    /*x*/ return;
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotAfterStatementsWithSingleBlankLines()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
 
                    return;
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotAfterStatementsWithSingleBlankLinesWithSpaces()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
 
                    return;
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotAfterStatementsWithMultipleBlankLines()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
 
                    return;
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotAfterStatementsOnMultipleLinesWithPPDirectiveBetween1()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
                    #pragma warning disable CS0001
                    return;
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotBetweenBlockAndElseClause()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
                    else
                    {
                    }
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotBetweenBlockAndOuterBlocker()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    if (true)
                    {
                        {
                        }
                    }
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotBetweenBlockAndCase()
    {
        var code =
            """
            class C
            {
                void M()
                {
                    switch (0)
                    {
                        case 0:
                        {
                            break;
                        }
                        case 1:
                            break;
                    }
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestBetweenBlockAndStatement1()
    {
        await new Verify.Test
        {
            TestCode = """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    [|}|]
                    return;
                }
            }
            """,
            FixedCode = """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
 
                    return;
                }
            }
            """,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestNotBetweenBlockAndStatement1_WhenOptionOff()
    {
        var code = """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
                    return;
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.TrueWithSilentEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestBetweenSwitchAndStatement1()
    {
        await new Verify.Test
        {
            TestCode = """
            class C
            {
                void M()
                {
                    switch (0)
                    {
                    [|}|]
                    return;
                }
            }
            """,
            FixedCode = """
            class C
            {
                void M()
                {
                    switch (0)
                    {
                    }
 
                    return;
                }
            }
            """,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestBetweenBlockAndStatement2()
    {
        await new Verify.Test
        {
            TestCode = """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    [|}|] // trailing comment
                    return;
                }
            }
            """,
            FixedCode = """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    } // trailing comment
 
                    return;
                }
            }
            """,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestBetweenBlockAndStatement3()
    {
        await new Verify.Test
        {
            TestCode = """
            class C
            {
                void M()
                {
                    if (true) { [|}|]
                    return;
                }
            }
            """,
            FixedCode = """
            class C
            {
                void M()
                {
                    if (true) { }
 
                    return;
                }
            }
            """,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestBetweenBlockAndStatement4()
    {
        await new Verify.Test
        {
            TestCode = """
            class C
            {
                void M()
                {
                    switch (0)
                    {
                    case 0:
                        if (true) { [|}|]
                        return;
                    }
                }
            }
            """,
            FixedCode = """
            class C
            {
                void M()
                {
                    switch (0)
                    {
                    case 0:
                        if (true) { }
 
                        return;
                    }
                }
            }
            """,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestFixAll1()
    {
        await new Verify.Test
        {
            TestCode = """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    [|}|]
                    return;
                    if (true)
                    {
                    [|}|]
                    return;
                }
            }
            """,
            FixedCode = """
            class C
            {
                void M()
                {
                    if (true)
                    {
                    }
 
                    return;
                    if (true)
                    {
                    }
 
                    return;
                }
            }
            """,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestSA1513NegativeCases()
    {
        var code = """
            using System;
            using System.Linq;
            using System.Collections.Generic;
            public class Foo
            {
                private int x;
                // Valid #1
                public int Bar
                {
                    get { return this.x; }
                    set { this.x = value; }
                }
                public void Baz()
                {
                    // Valid #2
                    try
                    {
                        this.x++;
                    }
                    catch (Exception)
                    {
                        this.x = 0;
                    }
                    finally
                    {
                        this.x++;
                    }
                    // Valid #3
                    do
                    {
                        this.x++;
                    }
                    while (this.x < 10);
                    // Valid #4
                    if (this.x > 0)
                    {
                        this.x++;
                    }
                    else
                    {
                        this.x = 0;
                    }
                    // Valid #5
                    var y = new[] { 1, 2, 3 };
                    // Valid #6
                    if (this.x > 0)
                    {
                        if (y != null)
                        {
                            this.x = -this.x;
                        }
                    }
                    // Valid #7
                    if (this.x > 0)
                    {
                        this.x = 0;
                    }
            #if !SOMETHING
                    else        
                    {
                        this.x++;    
                    }
            #endif
                    // Valid #8
            #if !SOMETHING
                    if (this.x > 0)
                    {
                        this.x = 0;
                    }
            #else
                    if (this.x < 0)        
                    {
                        this.x++;    
                    }
            #endif
                    // Valid #9
                    var q1 = 
                        from a in new[] 
                        {
                            1,
                            2,
                            3
                        }
                        from b in new[] { 4, 5, 6}
                        select a*b;
                    // Valid #10
                    var q2 = 
                        from a in new[] 
                        { 
                            1,
                            2,
                            3
                        }
                        let b = new[] 
                        { 
                            a, 
                            a * a, 
                            a * a * a 
                        }
                        select b;
                    // Valid #11
                    var q3 = 
                        from a in new[] 
                        {
                            1,
                            2,
                            3
                        }
                        where a > 0
                        select a;
                    // Valid #12
                    var q4 = 
                        from a in new[] 
                        {
                            new { Number = 1 },
                            new { Number = 2 },
                            new { Number = 3 }
                        }
                        join b in new[] 
                        { 
                            new { Number = 2 },
                            new { Number = 3 },
                            new { Number = 4 }
                        }
                        on a.Number equals b.Number
                        select new { Number1 = a.Number, Number2 = b.Number };
                    // Valid #13
                    var q5 = 
                        from a in new[] 
                        {
                            new { Number = 1 },
                            new { Number = 2 },
                            new { Number = 3 }
                        }
                        orderby a.Number descending
                        select a;
                    // Valid #14
                    var q6 = 
                        from a in new[] 
                        { 
                            1,
                            2,
                            3
                        }
                        group new
                        {
                            Number = a,
                            Square = a * a
                        }
                        by a;
                    // Valid #15
                    var d = new[]
                    {
                        1, 2, 3
                    };
                    // Valid #16
                    this.Qux(i =>
                    {
                        return d[i] * 2;
                    });
                    // Valid #17
                    if (this.x > 2)
                    {
                        this.x = 3;
                    } /* Some comment */
                    // Valid #18
                    int[] testArray;
                    testArray =
                        new[]
                        {
                            1
                        };
                    // Valid #19
                    var z1 = new object[]
                    {
                        new
                        {
                            Id = 12
                        },
                        new
                        {
                            Id = 13
                        }
                    };
                    // Valid #20
                    var z2 = new System.Action[]
                    {
                        () =>
                        {
                            this.x = 3;
                        },
                        () =>
                        {
                            this.x = 4;
                        }
                    };
                    // Valid #21
                    var z3 = new
                    {
                        Value1 = new
                        {   
                            Id = 12
                        },
                        Value2 = new
                        {
                            Id = 13
                        }
                    };
                    // Valid #22
                    var z4 = new System.Collections.Generic.List<object>
                    {
                        new
                        {
                            Id = 12
                        },
                        new
                        {
                            Id = 13
                        }
                    };
                }
                public void Qux(Func<int, int> function)
                {
                    this.x = function(this.x);
                }
                public Func<int, int> Quux()
                {
                    // Valid #23
            #if SOMETHING
                    return null;
            #else
                    return value =>
                    {
                        return value * 2;
                    };
            #endif
                }
                // Valid #24 (will be handled by SA1516)
                public int Corge
                {
                    get 
                    { 
                        return this.x; 
                    }
                    set { this.x = value; }
                }
                // Valid #25 (will be handled by SA1516)
                public int Grault
                {
                    set 
                    { 
                        this.x = value; 
                    }
                    get 
                    { 
                        return this.x; 
                    }
                }
                // Valid #26 (will be handled by SA1516)
                public event EventHandler Garply
                {
                    add
                    {
                    }
                    remove
                    {
                    }
                }
                // Valid #27 (will be handled by SA1516)
                public event EventHandler Waldo
                {
                    remove
                    {
                    }
                    add
                    {
                    }
                }
                // Valid #28 - Test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1020
                private static IEnumerable<object> Method()
                {
                    yield return new
                    {
                        prop = "A"
                    };
                }
                // This is a regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/784
                public void MultiLineLinqQuery()
                {
                    var someQuery = (from f in Enumerable.Empty<int>()
                                     where f != 0
                                     select new { Fish = "Face" }).ToList();
                    var someOtherQuery = (from f in Enumerable.Empty<int>()
                                          where f != 0
                                          select new
                                          {
                                              Fish = "AreFriends",
                                              Not = "Food"
                                          }).ToList();
                }
                // This is a regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/2306
                public void MultiLineGroupByLinqQuery()
                {
                    var someQuery = from f in Enumerable.Empty<int>()
                                    group f by new
                                    {
                                        f,
                                    }
                                    into a
                                    select a;
                    var someOtherQuery = from f in Enumerable.Empty<int>()
                                         group f by new { f }
                                         into a
                                         select a;
                }
                // This is a regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1049
                public object[] ExpressionBodiedProperty =>
                    new[]
                    {
                        new object()
                    };
                // This is a regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1049
                public object[] ExpressionBodiedMethod() =>
                    new[]
                    {
                        new object()
                    };
                // This is a regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1049
                public object[] GetterOnlyAutoProperty1 { get; } =
                    new[]
                    {
                        new object()
                    };
                // This is a regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1049
                public object[] GetterOnlyAutoProperty2 { get; } =
                    {
                    };
                // This is a regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1173
                bool contained =
                    new[]
                    {
                        1,
                        2,
                        3
                    }
                    .Contains(3);
                // This is a regression test for https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/1583
                public void TestTernaryConstruction()
                {
                    var target = contained
                        ? new Dictionary<string, string>
                            {
                                { "target", "_parent" }
                            }
                        : new Dictionary<string, string>();
                }
            }
            """;
 
        await new Verify.Test
        {
            TestCode = code,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
 
    [Fact]
    public async Task TestSA1513PositiveCases()
    {
        await new Verify.Test
        {
            TestCode = """
            using System;
            using System.Collections.Generic;
            public class Goo
            {
                private int x;
                // Invalid #1
                public int Property1
                {
                    get
                    {        
                        return this.x;
                    }
                    set
                    {
                        this.x = value;
                    }
                    /* some comment */
                }
                // Invalid #2
                public int Property2
                {
                    get { return this.x; }
                }
                public void Baz()
                {
                    // Invalid #3
                    switch (this.x)
                    {
                        case 1:
                        {
                            this.x = 1;
                            break;
                        }
                        case 2:
                            this.x = 2;
                            break;
                    }
                    // Invalid #4
                    {
                        var temp = this.x;
                        this.x = temp * temp;
                    [|}|]
                    this.x++;
                    // Invalid #5
                    if (this.x > 1)
                    {
                        this.x = 1;
                    [|}|]
                    if (this.x < 0)
                    {
                        this.x = 0;
                    [|}|]
                    switch (this.x)
                    {
                        // Invalid #6
                        case 0:
                        if (this.x < 0)
                        {
                            this.x = -1;
                        [|}|]
                        break;
                        // Invalid #7
                        case 1:
                        {
                            var temp = this.x * this.x;
                            this.x = temp;
                        [|}|]
                        break;
                    }
                }
                public void Example()
                {
                    new List<Action>
                    {
                        () =>
                        {
                            if (true)
                            {
                                return;
                            [|}|]
                            return;
                        }
                    };
                }
            }
            """,
            FixedCode = """
            using System;
            using System.Collections.Generic;
            public class Goo
            {
                private int x;
                // Invalid #1
                public int Property1
                {
                    get
                    {        
                        return this.x;
                    }
                    set
                    {
                        this.x = value;
                    }
                    /* some comment */
                }
                // Invalid #2
                public int Property2
                {
                    get { return this.x; }
                }
                public void Baz()
                {
                    // Invalid #3
                    switch (this.x)
                    {
                        case 1:
                        {
                            this.x = 1;
                            break;
                        }
                        case 2:
                            this.x = 2;
                            break;
                    }
                    // Invalid #4
                    {
                        var temp = this.x;
                        this.x = temp * temp;
                    }
 
                    this.x++;
                    // Invalid #5
                    if (this.x > 1)
                    {
                        this.x = 1;
                    }
 
                    if (this.x < 0)
                    {
                        this.x = 0;
                    }
 
                    switch (this.x)
                    {
                        // Invalid #6
                        case 0:
                        if (this.x < 0)
                        {
                            this.x = -1;
                        }
 
                        break;
                        // Invalid #7
                        case 1:
                        {
                            var temp = this.x * this.x;
                            this.x = temp;
                        }
 
                        break;
                    }
                }
                public void Example()
                {
                    new List<Action>
                    {
                        () =>
                        {
                            if (true)
                            {
                                return;
                            }
 
                            return;
                        }
                    };
                }
            }
            """,
            Options = { { CodeStyleOptions2.AllowStatementImmediatelyAfterBlock, CodeStyleOption2.FalseWithSuggestionEnforcement } }
        }.RunAsync();
    }
}