File: CodeGeneration\CodeGenerationTests.Shared.cs
Web Access
Project: src\src\EditorFeatures\Test\Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.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.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeGeneration;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.UnitTests.CodeGeneration;
 
public sealed partial class CodeGenerationTests
{
    [UseExportProvider]
    public class Shared
    {
        [Fact, Trait(Traits.Feature, Traits.Features.CodeGenerationSortDeclarations)]
        public async Task TestSorting()
        {
            var initial = "namespace [|N|] { }";
            var generationSource = """
                using System;
 
                namespace N
                {
                    public class [|C|]
                    {
                        private delegate void DAccessA();
                        internal delegate void DAccessB();
                        protected internal delegate void DAccessC();
                        protected delegate void DAccessD();
                        public delegate void DAccessE();
                        public delegate void DGeneric<T1, T2>(T1 a, T2 b);
                        public delegate void DGeneric<T>(T t, int i);
 
                        public class CNotStatic { }
                        public static class CStatic { }
                        private class CAccessA { }
                        internal class CAccessB { }
                        protected internal class CAccessC { }
                        protected class CAccessD { }
                        public class CAccessE { }
                        public class CGeneric<T1, T2> { }
                        public class CGeneric<T> { }
 
                        private struct SAccessA { }
                        internal struct SAccessB { }
                        protected internal struct SAccessC { }
                        protected struct SAccessD { }
                        public struct SAccessE { }
                        public struct SGeneric<T1, T2> { }
                        public struct SGeneric<T> { }
                        public struct SNameB { }
                        public struct SNameA { }
 
                        private enum EAccessA { }
                        internal enum EAccessB { }
                        protected internal enum EAccessC { }
                        protected enum EAccessD { }
                        public enum EAccessE { }
                        public enum ENameB { }
                        public enum ENameA { }
 
                        private interface IAccessA { }
                        internal interface IAccessB { }
                        protected internal interface IAccessC { }
                        protected interface IAccessD { }
                        public interface IAccessE { }
                        public interface IGeneric<T1, T2> { }
                        public interface IGeneric<T> { }
 
                        public static C operator !(C c) { return c; }
                        public static C operator +(C c) { return c; }
 
                        public void MNotStatic() { }
                        public static void MStatic() { }
                        private void MAccessA() { }
                        internal void MAccessB() { }
                        protected internal void MAccessC() { }
                        protected void MAccessD() { }
                        public void MAccessE() { }
                        public void MGeneric<T1, T2>() { }
                        public void MGeneric<T>(int param) { }
                        public void MGeneric<T>() { }
 
                        public int M2NotStatic() { return 0; }
                        public static int M2Static() { return 0; }
                        private int M2AccessA() { return 0; }
                        internal int M2AccessB() { return 0; }
                        protected internal int M2AccessC() { return 0; }
                        protected int M2AccessD() { return 0; }
                        public int M2AccessE() { return 0; }
                        public int M2Generic<T1, T2>() { return 0; }
                        public int M2Generic<T>(int param) { return 0; }
                        public int M2Generic<T>() { return 0; }
 
                        public int PNotStatic { get { return 0; } }
                        public static int PStatic { get { return 0; } }
                        private int PAccessA { get { return 0; } }
                        internal int PAccessB { get { return 0; } }
                        protected internal int PAccessC { get { return 0; } }
                        protected int PAccessD { get { return 0; } }
                        public int PAccessE { get { return 0; } }
 
                        public int this[int index1, int index2] { get { return 0; } }
                        public int this[int index] { get { return 0; } }
 
                        public event Action EFNotStatic;
                        public static event Action EFStatic;
                        private event Action EFAccessA;
                        internal event Action EFAccessB;
                        protected event Action EFAccessC;
                        protected internal event Action EFAccessD;
                        public event Action EFAccessE;
 
                        private C(string s);
                        internal C(long l);
                        protected C(char c);
                        protected internal C(short s);
                        public C(int a);
                        public C(int a, int b);
                        public C();
 
                        public string FNotStatic;
                        public static string FStatic;
                        public string FNotConst;
                        public const string FConst = "Const, Indeed";
                        private string FAccessA;
                        internal string FAccessB;
                        protected string FAccessC;
                        protected internal string FAccessD;
                        public string FAccessE;
                    }
                }
                """;
            var expected = """
                namespace N
                {
                    public class C
                    {
                        public const string FConst;
                        public static string FStatic;
                        public string FNotStatic;
                        public string FNotConst;
                        public string FAccessE;
                        protected string FAccessC;
                        protected internal string FAccessD;
                        internal string FAccessB;
                        private string FAccessA;
 
                        public C();
                        public C(int a);
                        public C(int a, int b);
                        protected C(char c);
                        protected internal C(short s);
                        internal C(long l);
                        private C(string s);
 
                        public int this[int index] { get; }
                        public int this[int index1, int index2] { get; }
 
                        public static int PStatic { get; }
                        public int PNotStatic { get; }
                        public int PAccessE { get; }
                        protected int PAccessD { get; }
                        protected internal int PAccessC { get; }
                        internal int PAccessB { get; }
                        private int PAccessA { get; }
 
                        public static event Action EFStatic;
                        public event Action EFNotStatic;
                        public event Action EFAccessE;
                        protected event Action EFAccessC;
                        protected internal event Action EFAccessD;
                        internal event Action EFAccessB;
                        private event Action EFAccessA;
 
                        public static int M2Static();
                        public static void MStatic();
                        public int M2AccessE();
                        public int M2Generic<T1, T2>();
                        public int M2Generic<T>(int param);
                        public int M2Generic<T>();
                        public int M2NotStatic();
                        public void MAccessE();
                        public void MGeneric<T1, T2>();
                        public void MGeneric<T>(int param);
                        public void MGeneric<T>();
                        public void MNotStatic();
                        protected int M2AccessD();
                        protected void MAccessD();
                        protected internal int M2AccessC();
                        protected internal void MAccessC();
                        internal int M2AccessB();
                        internal void MAccessB();
                        private int M2AccessA();
                        private void MAccessA();
 
                        public static C operator +(C c);
                        public static C operator !(C c);
 
                        public enum EAccessE
                        {
                        }
 
                        public enum ENameB
                        {
                        }
 
                        public enum ENameA
                        {
                        }
 
                        protected enum EAccessD
                        {
                        }
 
                        protected internal enum EAccessC
                        {
                        }
 
                        internal enum EAccessB
                        {
                        }
 
                        private enum EAccessA
                        {
                        }
 
                        public interface IAccessE
                        {
                        }
 
                        public interface IGeneric<T1, T2>
                        {
                        }
 
                        public interface IGeneric<T>
                        {
                        }
 
                        protected interface IAccessD
                        {
                        }
 
                        protected internal interface IAccessC
                        {
                        }
 
                        internal interface IAccessB
                        {
                        }
 
                        private interface IAccessA
                        {
                        }
 
                        public struct SAccessE
                        {
                        }
 
                        public struct SGeneric<T1, T2>
                        {
                        }
 
                        public struct SGeneric<T>
                        {
                        }
 
                        public struct SNameB
                        {
                        }
 
                        public struct SNameA
                        {
                        }
 
                        protected struct SAccessD
                        {
                        }
 
                        protected internal struct SAccessC
                        {
                        }
 
                        internal struct SAccessB
                        {
                        }
 
                        private struct SAccessA
                        {
                        }
 
                        public static class CStatic
                        {
                        }
 
                        public class CNotStatic
                        {
                        }
 
                        public class CAccessE
                        {
                        }
 
                        public class CGeneric<T1, T2>
                        {
                        }
 
                        public class CGeneric<T>
                        {
                        }
 
                        protected class CAccessD
                        {
                        }
 
                        protected internal class CAccessC
                        {
                        }
 
                        internal class CAccessB
                        {
                        }
 
                        private class CAccessA
                        {
                        }
 
                        public delegate void DAccessE();
 
                        public delegate void DGeneric<T1, T2>(T1 a, T2 b);
 
                        public delegate void DGeneric<T>(T t, int i);
 
                        protected delegate void DAccessD();
 
                        protected internal delegate void DAccessC();
 
                        internal delegate void DAccessB();
 
                        private delegate void DAccessA();
                    }
                }
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected,
                context: new CodeGenerationContext(generateMethodBodies: false),
                forceLanguage: LanguageNames.CSharp);
 
            initial = "Namespace [|N|] \n End Namespace";
            expected = """
                Namespace N
                    Public Class C
                        Public Const FConst As String
                        Public Shared FStatic As String
                        Public FNotStatic As String
                        Public FNotConst As String
                        Public FAccessE As String
                        Protected FAccessC As String
                        Protected Friend FAccessD As String
                        Friend FAccessB As String
                        Private FAccessA As String
                        Public Sub New()
                        Public Sub New(a As Integer)
                        Public Sub New(a As Integer, b As Integer)
                        Protected Sub New(c As Char)
                        Protected Friend Sub New(s As Short)
                        Friend Sub New(l As Long)
                        Private Sub New(s As String)
                        Public Shared ReadOnly Property PStatic As Integer
                        Public ReadOnly Property PNotStatic As Integer
                        Public ReadOnly Property PAccessE As Integer
                        Default Public ReadOnly Property this[](index1 As Integer, index2 As Integer) As Integer
                        Default Public ReadOnly Property this[](index As Integer) As Integer
                        Protected ReadOnly Property PAccessD As Integer
                        Protected Friend ReadOnly Property PAccessC As Integer
                        Friend ReadOnly Property PAccessB As Integer
                        Private ReadOnly Property PAccessA As Integer
                        Public Shared Event EFStatic As Action
                        Public Event EFNotStatic As Action
                        Public Event EFAccessE As Action
                        Protected Event EFAccessC As Action
                        Protected Friend Event EFAccessD As Action
                        Friend Event EFAccessB As Action
                        Private Event EFAccessA As Action
                        Public Shared Sub MStatic()
                        Public Sub MNotStatic()
                        Public Sub MAccessE()
                        Public Sub MGeneric(Of T1, T2)()
                        Public Sub MGeneric(Of T)(param As Integer)
                        Public Sub MGeneric(Of T)()
                        Protected Sub MAccessD()
                        Protected Friend Sub MAccessC()
                        Friend Sub MAccessB()
                        Private Sub MAccessA()
                        Public Shared Function M2Static() As Integer
                        Public Function M2NotStatic() As Integer
                        Public Function M2AccessE() As Integer
                        Public Function M2Generic(Of T1, T2)() As Integer
                        Public Function M2Generic(Of T)(param As Integer) As Integer
                        Public Function M2Generic(Of T)() As Integer
                        Protected Function M2AccessD() As Integer
                        Protected Friend Function M2AccessC() As Integer
                        Friend Function M2AccessB() As Integer
                        Private Function M2AccessA() As Integer
                        Public Shared Operator +(c As C) As C
                        Public Shared Operator Not(c As C) As C
 
                        Public Enum EAccessE
                        End Enum
 
                        Public Enum ENameB
                        End Enum
 
                        Public Enum ENameA
                        End Enum
 
                        Protected Enum EAccessD
                        End Enum
 
                        Protected Friend Enum EAccessC
                        End Enum
 
                        Friend Enum EAccessB
                        End Enum
 
                        Private Enum EAccessA
                        End Enum
 
                        Public Interface IAccessE
                        End Interface
 
                        Public Interface IGeneric(Of T1, T2)
                        End Interface
 
                        Public Interface IGeneric(Of T)
                        End Interface
 
                        Protected Interface IAccessD
                        End Interface
 
                        Protected Friend Interface IAccessC
                        End Interface
 
                        Friend Interface IAccessB
                        End Interface
 
                        Private Interface IAccessA
                        End Interface
 
                        Public Structure SAccessE
                        End Structure
 
                        Public Structure SGeneric(Of T1, T2)
                        End Structure
 
                        Public Structure SGeneric(Of T)
                        End Structure
 
                        Public Structure SNameB
                        End Structure
 
                        Public Structure SNameA
                        End Structure
 
                        Protected Structure SAccessD
                        End Structure
 
                        Protected Friend Structure SAccessC
                        End Structure
 
                        Friend Structure SAccessB
                        End Structure
 
                        Private Structure SAccessA
                        End Structure
 
                        Public Class CNotStatic
                        End Class
 
                        Public Class CStatic
                        End Class
 
                        Public Class CAccessE
                        End Class
 
                        Public Class CGeneric(Of T1, T2)
                        End Class
 
                        Public Class CGeneric(Of T)
                        End Class
 
                        Protected Class CAccessD
                        End Class
 
                        Protected Friend Class CAccessC
                        End Class
 
                        Friend Class CAccessB
                        End Class
 
                        Private Class CAccessA
                        End Class
 
                        Public Delegate Sub DAccessE()
                        Public Delegate Sub DGeneric(Of T1, T2)(a As T1, b As T2)
                        Public Delegate Sub DGeneric(Of T)(t As T, i As Integer)
                        Protected Delegate Sub DAccessD()
                        Protected Friend Delegate Sub DAccessC()
                        Friend Delegate Sub DAccessB()
                        Private Delegate Sub DAccessA()
                    End Class
                End Namespace
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected,
                context: new CodeGenerationContext(generateMethodBodies: false),
                forceLanguage: LanguageNames.VisualBasic);
        }
 
        [Fact, Trait(Traits.Feature, Traits.Features.CodeGenerationSortDeclarations)]
        public async Task TestSortingDefaultTypeMemberAccessibility1()
        {
            var generationSource = "public class [|C|] { private string B; public string C; }";
            var initial = "public class [|C|] { string A; }";
            var expected = """
                public class C {
                    public string C;
                    string A;
                    private string B;
                }
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true);
 
            initial = "public struct [|S|] { string A; }";
            expected = """
                public struct S {
                    public string C;
                    string A;
                    private string B;
                }
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true);
 
            initial = "Public Class [|C|] \n Dim A As String \n End Class";
            expected = """
                Public Class C
                    Public C As String
                    Dim A As String
                    Private B As String
                End Class
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true);
 
            initial = "Public Module [|M|] \n Dim A As String \n End Module";
            expected = """
                Public Module M
                    Public C As String
                    Dim A As String
                    Private B As String
                End Module
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true);
 
            initial = "Public Structure [|S|] \n Dim A As String \n End Structure";
            expected = """
                Public Structure S 
                 Dim A As String
                    Public C As String
                    Private B As String
                End Structure
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true);
        }
 
        [Fact, Trait(Traits.Feature, Traits.Features.CodeGenerationSortDeclarations)]
        public async Task TestDefaultTypeMemberAccessibility2()
        {
            var codeGenOptionNoBody = new CodeGenerationContext(generateMethodBodies: false);
 
            var generationSource = "public class [|C|] { private void B(){} public void C(){}  }";
            var initial = "public interface [|I|] { void A(); }";
            var expected = """
                public interface I { void A();
                    void B();
                    void C();
                }
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true, context: codeGenOptionNoBody);
 
            initial = "Public Interface [|I|] \n Sub A() \n End Interface";
            expected = """
                Public Interface I 
                 Sub A()
                    Sub B()
                    Sub C()
                End Interface
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true, context: codeGenOptionNoBody);
 
            initial = "Public Class [|C|] \n Sub A() \n End Sub \n End Class";
            expected = """
                Public Class C 
                 Sub A() 
                 End Sub
 
                    Public Sub C()
                    End Sub
 
                    Private Sub B()
                    End Sub
                End Class
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true);
 
            initial = "Public Module [|M|] \n Sub A() \n End Sub \n End Module";
            expected = """
                Public Module M 
                 Sub A() 
                 End Sub
 
                    Public Sub C()
                    End Sub
 
                    Private Sub B()
                    End Sub
                End Module
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected, onlyGenerateMembers: true);
        }
 
        [Fact, Trait(Traits.Feature, Traits.Features.CodeGenerationSortDeclarations)]
        public async Task TestDefaultNamespaceMemberAccessibility1()
        {
            var generationSource = "internal class [|B|]{}";
            var initial = "namespace [|N|] { class A{} }";
            var expected = """
                namespace N { class A{}
 
                    internal class B
                    {
                    }
                }
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected);
 
            initial = "Namespace [|N|] \n Class A \n End Class \n End Namespace";
            expected = """
                Namespace N 
                 Class A 
                 End Class
 
                    Friend Class B
                    End Class
                End Namespace
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected);
        }
 
        [Fact, Trait(Traits.Feature, Traits.Features.CodeGenerationSortDeclarations)]
        public async Task TestDefaultNamespaceMemberAccessibility2()
        {
            var generationSource = "public class [|C|]{}";
            var initial = "namespace [|N|] { class A{} }";
            var expected = "namespace N { public class C { } class A{} }";
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected);
 
            initial = "Namespace [|N|] \n Class A \n End Class \n End Namespace";
            expected = """
                Namespace N
                    Public Class C
                    End Class
 
                    Class A 
                 End Class 
                 End Namespace
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, initial, expected);
        }
 
        [Fact, Trait(Traits.Feature, Traits.Features.MetadataAsSource)]
        public Task TestDocumentationComment()
            => TestGenerateFromSourceSymbolAsync("""
                public class [|C|]
                {
                    /// <summary>When in need, a documented method is a friend, indeed.</summary>
                    public C() { }
                }
                """, "public class [|C|] { }", """
                public class C
                {
                    /// 
                    /// <member name="M:C.#ctor">
                    ///     <summary>When in need, a documented method is a friend, indeed.</summary>
                    /// </member>
                    /// 
                    public C();
                }
                """,
                context: new CodeGenerationContext(generateMethodBodies: false, generateDocumentationComments: true),
                onlyGenerateMembers: true);
 
        [Fact, Trait(Traits.Feature, Traits.Features.CodeGeneration)]
        public async Task TestModifiers()
        {
            var generationSource = """
                namespace [|N|]
                {
                    public class A 
                    {
                        public virtual string Property { get { return null; } }
                        public static abstract string Property1 { get; }
 
                        public virtual void Method1() {}
                        public static abstract void Method2() {}
                    }
 
                    public class C
                    {
                        public sealed override string Property { get { return null; } }
                        public sealed override void Method1() {} 
                    }
                }
                """;
            await TestGenerateFromSourceSymbolAsync(generationSource, "namespace [|N|] { }", """
                namespace N {
                    namespace N
                    {
                        public class A
                        {
                            public static string Property1 { get; }
                            public virtual string Property { get; }
 
                            public static void Method2();
                            public virtual void Method1();
                        }
 
                        public class C
                        {
                            public sealed override string Property { get; }
 
                            public sealed override void Method1();
                        }
                    }
                }
                """,
                context: new CodeGenerationContext(generateMethodBodies: false));
            await TestGenerateFromSourceSymbolAsync(generationSource, "Namespace [|N|] End Namespace", """
                Namespace N End NamespaceNamespace N
                        Public Class A
                            Public Shared ReadOnly Property Property1 As String
                            Public Overridable ReadOnly Property [Property] As String
                            Public Shared Sub Method2()
                            Public Overridable Sub Method1()
                        End Class
 
                        Public Class C
                            Public Overrides NotOverridable ReadOnly Property [Property] As String
                            Public NotOverridable Overrides Sub Method1()
                        End Class
                    End Namespace
                """,
                context: new CodeGenerationContext(generateMethodBodies: false));
        }
    }
}