File: Symbols\MockSymbolTests.cs
Web Access
Project: src\src\Compilers\CSharp\Test\Symbol\Microsoft.CodeAnalysis.CSharp.Symbol.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.Symbol.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;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.UnitTests;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    public class SymbolTests
    {
        [Fact]
        public void TestArrayType()
        {
            CSharpCompilation compilation = CSharpCompilation.Create("Test");
 
            NamedTypeSymbol elementType = new MockNamedTypeSymbol("TestClass", Enumerable.Empty<Symbol>());   // this can be any type.
 
            ArrayTypeSymbol ats1 = ArrayTypeSymbol.CreateCSharpArray(compilation.Assembly, TypeWithAnnotations.Create(elementType), rank: 1);
            Assert.Equal(1, ats1.Rank);
            Assert.True(ats1.IsSZArray);
            Assert.Same(elementType, ats1.ElementType);
            Assert.Equal(SymbolKind.ArrayType, ats1.Kind);
            Assert.True(ats1.IsReferenceType);
            Assert.False(ats1.IsValueType);
            Assert.Equal("TestClass[]", ats1.ToTestDisplayString());
 
            ArrayTypeSymbol ats2 = ArrayTypeSymbol.CreateCSharpArray(compilation.Assembly, TypeWithAnnotations.Create(elementType), rank: 2);
            Assert.Equal(2, ats2.Rank);
            Assert.Same(elementType, ats2.ElementType);
            Assert.Equal(SymbolKind.ArrayType, ats2.Kind);
            Assert.True(ats2.IsReferenceType);
            Assert.False(ats2.IsValueType);
            Assert.Equal("TestClass[,]", ats2.ToTestDisplayString());
 
            ArrayTypeSymbol ats3 = ArrayTypeSymbol.CreateCSharpArray(compilation.Assembly, TypeWithAnnotations.Create(elementType), rank: 3);
            Assert.Equal(3, ats3.Rank);
            Assert.Equal("TestClass[,,]", ats3.ToTestDisplayString());
        }
 
        [Fact]
        public void TestPointerType()
        {
            NamedTypeSymbol pointedAtType = new MockNamedTypeSymbol("TestClass", Enumerable.Empty<Symbol>());   // this can be any type.
 
            PointerTypeSymbol pts1 = new PointerTypeSymbol(TypeWithAnnotations.Create(pointedAtType));
            Assert.Same(pointedAtType, pts1.PointedAtType);
            Assert.Equal(SymbolKind.PointerType, pts1.Kind);
            Assert.False(pts1.IsReferenceType);
            Assert.True(pts1.IsValueType);
            Assert.Equal("TestClass*", pts1.ToTestDisplayString());
        }
 
        [Fact]
        public void TestMissingMetadataSymbol()
        {
            AssemblyIdentity missingAssemblyId = new AssemblyIdentity("goo");
            AssemblySymbol assem = new MockAssemblySymbol("banana");
            ModuleSymbol module = new MissingModuleSymbol(assem, ordinal: -1);
            NamedTypeSymbol container = new MockNamedTypeSymbol("TestClass", Enumerable.Empty<Symbol>(), TypeKind.Class);
 
            var mms1 = new MissingMetadataTypeSymbol.TopLevel(new MissingAssemblySymbol(missingAssemblyId).Modules[0], "Elvis", "Lives", 2, true);
            Assert.Equal(2, mms1.Arity);
            Assert.Equal("Elvis", mms1.NamespaceName);
            Assert.Equal("Lives", mms1.Name);
            Assert.Equal("Elvis.Lives<,>[missing]", mms1.ToTestDisplayString());
            Assert.Equal("goo", mms1.ContainingAssembly.Identity.Name);
 
            var mms2 = new MissingMetadataTypeSymbol.TopLevel(module, "Elvis.Is", "Cool", 0, true);
            Assert.Equal(0, mms2.Arity);
            Assert.Equal("Elvis.Is", mms2.NamespaceName);
            Assert.Equal("Cool", mms2.Name);
            Assert.Equal("Elvis.Is.Cool[missing]", mms2.ToTestDisplayString());
            Assert.Same(assem, mms2.ContainingAssembly);
 
            // TODO: Add test for 3rd constructor.
        }
 
        [Fact]
        public void TestNamespaceExtent()
        {
            AssemblySymbol assem1 = new MockAssemblySymbol("goo");
 
            NamespaceExtent ne1 = new NamespaceExtent(assem1);
            Assert.Equal(NamespaceKind.Assembly, ne1.Kind);
            Assert.Same(ne1.Assembly, assem1);
 
            CSharpCompilation compilation = CSharpCompilation.Create("Test");
            NamespaceExtent ne2 = new NamespaceExtent(compilation);
            Assert.IsType<CSharpCompilation>(ne2.Compilation);
            Assert.Throws<InvalidOperationException>(() => ne1.Compilation);
        }
 
        private Symbol CreateMockSymbol(NamespaceExtent extent, XElement xel)
        {
            Symbol result;
            var childSymbols = from childElement in xel.Elements()
                               select CreateMockSymbol(extent, childElement);
 
            string name = xel.Attribute("name").Value;
            switch (xel.Name.LocalName)
            {
                case "ns":
                    result = new MockNamespaceSymbol(name, extent, childSymbols);
                    break;
 
                case "class":
                    result = new MockNamedTypeSymbol(name, childSymbols, TypeKind.Class);
                    break;
 
                default:
                    throw new InvalidOperationException("unexpected xml element");
            }
 
            foreach (IMockSymbol child in childSymbols)
            {
                child.SetContainer(result);
            }
 
            return result;
        }
 
        private void DumpSymbol(Symbol sym, StringBuilder builder, int level)
        {
            if (sym is NamespaceSymbol)
            {
                builder.AppendFormat("namespace {0} [{1}]", sym.Name, (sym as NamespaceSymbol).Extent);
            }
            else if (sym is NamedTypeSymbol)
            {
                builder.AppendFormat("{0} {1}", (sym as NamedTypeSymbol).TypeKind.ToString().ToLower(), sym.Name);
            }
            else
            {
                throw new InvalidOperationException("Unexpected symbol kind");
            }
 
            if (sym is NamespaceOrTypeSymbol namespaceOrType && namespaceOrType.GetMembers().Any())
            {
                builder.AppendLine(" { ");
                var q = from c in namespaceOrType.GetMembers()
                        orderby c.Name
                        select c;
 
                foreach (Symbol child in q)
                {
                    for (int i = 0; i <= level; ++i)
                    {
                        builder.Append("    ");
                    }
 
                    DumpSymbol(child, builder, level + 1);
                    builder.AppendLine();
                }
 
                for (int i = 0; i < level; ++i)
                {
                    builder.Append("    ");
                }
 
                builder.Append('}');
            }
        }
 
        private string DumpSymbol(Symbol sym)
        {
            StringBuilder builder = new StringBuilder();
            DumpSymbol(sym, builder, 0);
            return builder.ToString();
        }
 
        [Fact]
        public void TestMergedNamespaces()
        {
            NamespaceSymbol root1 = (NamespaceSymbol)CreateMockSymbol(new NamespaceExtent(new MockAssemblySymbol("Assem1")),
                                                                       XElement.Parse(
@"<ns name=''> 
    <ns name='A'> 
         <ns name='D'/>
         <ns name='E'/>
         <ns name='F'>
             <ns name='G'/>
         </ns>
    </ns> 
    <ns name='B'/>
    <ns name='C'/>
    <ns name='U'/>
    <class name='X'/>
</ns>"));
 
            NamespaceSymbol root2 = (NamespaceSymbol)CreateMockSymbol(new NamespaceExtent(new MockAssemblySymbol("Assem2")),
                                                                       XElement.Parse(
@"<ns name=''>
    <ns name='B'>
         <ns name='K'/>
    </ns>
    <ns name='C'/>
    <class name='X'/>
    <class name='Y'/>
</ns>"));
 
            NamespaceSymbol root3 = (NamespaceSymbol)CreateMockSymbol(new NamespaceExtent(new MockAssemblySymbol("Assem3")),
                                                                       XElement.Parse(
@"<ns name=''> 
    <ns name='A'>
        <ns name='D'/>
        <ns name='E'>
           <ns name='H'/>
        </ns>
    </ns> 
    <ns name='B'>
        <ns name='K'>
            <ns name='L'/>
            <class name='L'/>
        </ns>
    </ns> 
    <class name='Z'/>
</ns>"));
 
            NamespaceSymbol merged = MergedNamespaceSymbol.Create(new NamespaceExtent(new MockAssemblySymbol("Merged")), null,
                                                                  new NamespaceSymbol[] { root1, root2, root3 }.AsImmutable());
            string expected =
@"namespace  [Assembly: Merged] { 
    namespace A [Assembly: Merged] { 
        namespace D [Assembly: Merged]
        namespace E [Assembly: Merged] { 
            namespace H [Assembly: Assem3]
        }
        namespace F [Assembly: Assem1] { 
            namespace G [Assembly: Assem1]
        }
    }
    namespace B [Assembly: Merged] { 
        namespace K [Assembly: Merged] { 
            class L
            namespace L [Assembly: Assem3]
        }
    }
    namespace C [Assembly: Merged]
    namespace U [Assembly: Assem1]
    class X
    class X
    class Y
    class Z
}".Replace("Assembly: Merged", "Assembly: Merged, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")
  .Replace("Assembly: Assem1", "Assembly: Assem1, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")
  .Replace("Assembly: Assem3", "Assembly: Assem3, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null");
 
            Assert.Equal(expected, DumpSymbol(merged));
 
            NamespaceSymbol merged2 = MergedNamespaceSymbol.Create(new NamespaceExtent(new MockAssemblySymbol("Merged2")), null,
                                                                  new NamespaceSymbol[] { root1 }.AsImmutable());
            Assert.Same(merged2, root1);
        }
    }
 
    internal interface IMockSymbol
    {
        void SetContainer(Symbol container);
    }
}