File: Organizing\OrganizeTypeDeclarationTests.cs
Web Access
Project: ..\..\..\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures.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.
 
#nullable disable
 
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.Editor.Commanding.Commands;
using Microsoft.CodeAnalysis.Editor.Implementation.Organizing;
using Microsoft.CodeAnalysis.Editor.Shared.Utilities;
using Microsoft.CodeAnalysis.Editor.UnitTests;
using Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Organizing
{
    public class OrganizeTypeDeclarationTests : AbstractOrganizerTests
    {
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        [InlineData("record class")]
        [InlineData("record struct")]
        public async Task TestFieldsWithoutInitializers1(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int A;
    int B;
    int C;
}}";
 
            var final =
$@"{typeKind} C {{
    int A;
    int B;
    int C;
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("struct")]
        [InlineData("record")]
        [InlineData("record class")]
        [InlineData("record struct")]
        public async Task TestNestedTypes(string typeKind)
        {
            var initial =
$@"class C {{
    {typeKind} Nested1 {{ }}
    {typeKind} Nested2 {{ }}
    int A;
}}";
 
            var final =
$@"class C {{
    int A;
    {typeKind} Nested1 {{ }}
    {typeKind} Nested2 {{ }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestFieldsWithoutInitializers2(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int C;
    int B;
    int A;
}}";
 
            var final =
$@"{typeKind} C {{
    int A;
    int B;
    int C;
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        [InlineData("record struct")]
        public async Task TestFieldsWithInitializers1(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int C = 0;
    int B;
    int A;
}}";
 
            var final =
$@"{typeKind} C {{
    int A;
    int B;
    int C = 0;
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestFieldsWithInitializers2(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int C = 0;
    int B = 0;
    int A;
}}";
 
            var final =
$@"{typeKind} C {{
    int A;
    int C = 0;
    int B = 0;
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestEventFieldDeclaration(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    public void Goo() {{}}
    public event EventHandler MyEvent;
}}";
 
            var final =
$@"{typeKind} C {{
    public event EventHandler MyEvent;
    public void Goo() {{}}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestEventDeclaration(string typeKind)
        {
            var initial =
$@"{typeKind} C  {{
    public void Goo() {{}}
    public event EventHandler Event
    {{
        remove {{ }}
        add {{ }}
    }}
 
    public static int Property {{ get; set; }}
}}";
 
            var final =
$@"{typeKind} C  {{
    public static int Property {{ get; set; }}
    public event EventHandler Event
    {{
        remove {{ }}
        add {{ }}
    }}
 
    public void Goo() {{}}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestOperator(string typeKind)
        {
            var initial =
$@"{typeKind} C  {{
    public void Goo() {{}}
    public static int operator +(Goo<T> a, int b)
    {{
        return 1;
    }}
}}";
 
            var final =
$@"{typeKind} C  {{
    public static int operator +(Goo<T> a, int b)
    {{
        return 1;
    }}
    public void Goo() {{}}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestIndexer(string typeKind)
        {
            var initial =
$@"{typeKind} C  {{
    public void Goo() {{}}
    public T this[int i]
    {{
        get
        {{
            return default(T);
        }}
    }}
 
    C() {{}}
}}";
 
            var final =
$@"{typeKind} C  {{
    C() {{}}
    public T this[int i]
    {{
        get
        {{
            return default(T);
        }}
    }}
 
    public void Goo() {{}}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestConstructorAndDestructors(string typeKind)
        {
            var initial =
$@"{typeKind} C  {{
    public ~Goo() {{}}
    enum Days {{Sat, Sun}};
    public Goo() {{}}
}}";
 
            var final =
$@"{typeKind} C  {{
    public Goo() {{}}
    public ~Goo() {{}}
    enum Days {{Sat, Sun}};
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestInterface(string typeKind)
        {
            var initial =
$@"{typeKind} C  {{}}
interface I
{{
   void Goo();
   int Property {{ get; set; }}
   event EventHandler Event;
}}";
 
            var final =
$@"{typeKind} C  {{}}
interface I
{{
   event EventHandler Event;
   int Property {{ get; set; }}
   void Goo();
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestStaticInstance(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int A;
    static int B;
    int C;
    static int D;
}}";
 
            var final =
$@"{typeKind} C {{
    static int B;
    static int D;
    int A;
    int C;
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        [InlineData("record struct")]
        public async Task TestAccessibility(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int A;
    private int B;
    internal int C;
    protected int D;
    public int E;
    protected internal int F;
}}";
 
            var final =
$@"{typeKind} C {{
    public int E;
    protected int D;
    protected internal int F;
    internal int C;
    int A;
    private int B;
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestStaticAccessibility(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int A1;
    private int B1;
    internal int C1;
    protected int D1;
    public int E1;
    static int A2;
    static private int B2;
    static internal int C2;
    static protected int D2;
    static public int E2;
}}";
 
            var final =
$@"{typeKind} C {{
    public static int E2;
    protected static int D2;
    internal static int C2;
    static int A2;
    private static int B2;
    public int E1;
    protected int D1;
    internal int C1;
    int A1;
    private int B1;
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestGenerics(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    void B<X,Y>();
    void B<Z>();
    void B();
    void A<X,Y>();
    void A<Z>();
    void A();
}}";
 
            var final =
$@"{typeKind} C {{
    void A();
    void A<Z>();
    void A<X,Y>();
    void B();
    void B<Z>();
    void B<X,Y>();
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestInsidePPRegion(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
#if true
    int c;
    int b;
    int a;
#endif
}}";
 
            var final =
$@"{typeKind} C {{
#if true
    int a;
    int b;
    int c;
#endif
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestInsidePPRegion2(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
#if true
    int z;
    int y;
    int x;
#endif
#if true
    int c;
    int b;
    int a;
#endif
}}";
 
            var final =
$@"{typeKind} C {{
#if true
    int x;
    int y;
    int z;
#endif
#if true
    int a;
    int b;
    int c;
#endif
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestInsidePPRegion3(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int z;
    int y;
#if true
    int x;
    int c;
#endif
    int b;
    int a;
}}";
 
            var final =
$@"{typeKind} C {{
    int y;
    int z;
#if true
    int c;
    int x;
#endif
    int a;
    int b;
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestInsidePPRegion4(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int c() {{
    }}
    int b {{
    }}
    int a {{
#if true
#endif
    }}
}}";
 
            var final =
$@"{typeKind} C {{
    int a {{
#if true
#endif
    }}
    int b {{
    }}
    int c() {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestInsidePPRegion5(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int c() {{
    }}
    int b {{
    }}
    int a {{
#if true
#else
#endif
    }}
}}";
 
            var final =
$@"{typeKind} C {{
    int a {{
#if true
#else
#endif
    }}
    int b {{
    }}
    int c() {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestInsidePPRegion6(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
#region
    int e() {{
    }}
    int d() {{
    }}
    int c() {{
#region
    }}
#endregion
    int b {{
    }}
    int a {{
    }}
#endregion
}}";
 
            var final =
$@"{typeKind} C {{
#region
    int d() {{
    }}
    int e() {{
    }}
    int c() {{
#region
    }}
#endregion
    int a {{
    }}
    int b {{
    }}
#endregion
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestPinned(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int z() {{
    }}
    int y() {{
    }}
    int x() {{
#if true
    }}
    int n;
    int m;
    int c() {{
#endif
    }}
    int b() {{
    }}
    int a() {{
    }}
}}";
 
            var final =
$@"{typeKind} C {{
    int y() {{
    }}
    int z() {{
    }}
    int x() {{
#if true
    }}
    int m;
    int n;
    int c() {{
#endif
    }}
    int a() {{
    }}
    int b() {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, Trait(Traits.Feature, Traits.Features.Organizing)]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestSensitivity(string typeKind)
        {
            var initial =
$@"{typeKind} C {{
    int Bb;
    int B;
    int bB;
    int b;
    int Aa;
    int a;
    int A;
    int aa;
    int aA;
    int AA;
    int bb;
    int BB;
    int bBb;
    int bbB;
    int あ;
    int ア;
    int ア;
    int ああ;
    int あア;
    int あア;
    int アあ;
    int cC;
    int Cc;
    int アア;
    int アア;
    int アあ;
    int アア;
    int アア;
    int BBb;
    int BbB;
    int bBB;
    int BBB;
    int c;
    int C;
    int bbb;
    int Bbb;
    int cc;
    int cC;
    int CC;
}}";
 
            var final =
$@"{typeKind} C {{
    int a;
    int A;
    int aa;
    int aA;
    int Aa;
    int AA;
    int b;
    int B;
    int bb;
    int bB;
    int Bb;
    int BB;
    int bbb;
    int bbB;
    int bBb;
    int bBB;
    int Bbb;
    int BbB;
    int BBb;
    int BBB;
    int c;
    int C;
    int cc;
    int cC;
    int cC;
    int Cc;
    int CC;
    int ア;
    int ア;
    int あ;
    int アア;
    int アア;
    int アア;
    int アア;
    int アあ;
    int アあ;
    int あア;
    int あア;
    int ああ;
}}";
 
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestWhitespaceBetweenMethods1(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
    void B()
    {{
    }}
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
    void A()
    {{
    }}
 
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestWhitespaceBetweenMethods2(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
    void B()
    {{
    }}
 
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
    void A()
    {{
    }}
 
 
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestWhitespaceBetweenMethods3(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
 
    void B()
    {{
    }}
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
 
    void A()
    {{
    }}
 
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestWhitespaceBetweenMethods4(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
 
 
    void B()
    {{
    }}
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
 
 
    void A()
    {{
    }}
 
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestWhitespaceBetweenMethods5(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
 
 
    void B()
    {{
    }}
 
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
 
 
    void A()
    {{
    }}
 
 
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestWhitespaceBetweenMethods6(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
 
 
    void B()
    {{
    }}
 
 
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
 
 
    void A()
    {{
    }}
 
 
 
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestMoveComments1(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
    // B
    void B()
    {{
    }}
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
    void A()
    {{
    }}
 
    // B
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestMoveComments2(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
    // B
    void B()
    {{
    }}
 
    // A
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
    // A
    void A()
    {{
    }}
 
    // B
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestMoveDocComments1(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
    /// B
    void B()
    {{
    }}
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
    void A()
    {{
    }}
 
    /// B
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestMoveDocComments2(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
    /// B
 
    void B()
    {{
    }}
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
    void A()
    {{
    }}
 
    /// B
 
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestDontMoveBanner(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
    // Banner
 
    void B()
    {{
    }}
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
    // Banner
 
    void A()
    {{
    }}
 
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [Theory, WorkItem("http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/537614")]
        [InlineData("class")]
        [InlineData("record")]
        public async Task TestDontMoveBanner2(string typeKind)
        {
            var initial =
$@"{typeKind} Program
{{
    // Banner
 
    // More banner
    // Bannery stuff
 
    void B()
    {{
    }}
 
    void A()
    {{
    }}
}}";
 
            var final =
$@"{typeKind} Program
{{
    // Banner
 
    // More banner
    // Bannery stuff
 
    void A()
    {{
    }}
 
    void B()
    {{
    }}
}}";
            await CheckAsync(initial, final);
        }
 
        [WpfFact]
        [Trait(Traits.Feature, Traits.Features.Organizing)]
        [Trait(Traits.Feature, Traits.Features.Interactive)]
        public void OrganizingCommandsDisabledInSubmission()
        {
            using var workspace = TestWorkspace.Create(XElement.Parse(@"
                <Workspace>
                    <Submission Language=""C#"" CommonReferences=""true"">  
                        class C
                        {
                            object $$goo;
                        }
                    </Submission>
                </Workspace> "),
                workspaceKind: WorkspaceKind.Interactive,
                composition: EditorTestCompositions.EditorFeaturesWpf);
            // Force initialization.
            workspace.GetOpenDocumentIds().Select(id => workspace.GetTestDocument(id).GetTextView()).ToList();
 
            var textView = workspace.Documents.Single().GetTextView();
 
            var handler = new OrganizeDocumentCommandHandler(
                workspace.GetService<IThreadingContext>(),
                workspace.GlobalOptions);
 
            var state = handler.GetCommandState(new SortAndRemoveUnnecessaryImportsCommandArgs(textView, textView.TextBuffer));
            Assert.True(state.IsUnspecified);
 
            state = handler.GetCommandState(new OrganizeDocumentCommandArgs(textView, textView.TextBuffer));
            Assert.True(state.IsUnspecified);
        }
    }
}