File: EmitMetadataTestBase.cs
Web Access
Project: src\src\Compilers\Test\Utilities\CSharp\Microsoft.CodeAnalysis.CSharp.Test.Utilities.csproj (Microsoft.CodeAnalysis.CSharp.Test.Utilities)
// 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.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Metadata;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
{
    public abstract class EmitMetadataTestBase : CSharpTestBase
    {
        internal static XElement DumpTypeInfo(ModuleSymbol moduleSymbol)
        {
            return LoadChildNamespace(moduleSymbol.GlobalNamespace);
        }
 
        internal static XElement LoadChildNamespace(NamespaceSymbol n)
        {
            XElement elem = new XElement((n.Name.Length == 0 ? "Global" : n.Name));
 
            var childrenTypes = n.GetTypeMembers().OrderBy((t) => t, new NameAndArityComparer());
 
            elem.Add(from t in childrenTypes select LoadChildType(t));
 
            var childrenNS = n.GetMembers().
                                OfType<NamespaceSymbol>().
                                OrderBy(child => child.Name, StringComparer.OrdinalIgnoreCase);
 
            elem.Add(from c in childrenNS select LoadChildNamespace(c));
 
            return elem;
        }
 
        private static XElement LoadChildType(NamedTypeSymbol t)
        {
            XElement elem = new XElement("type");
 
            elem.Add(new XAttribute("name", t.Name));
 
            if (t.Arity > 0)
            {
                string typeParams = string.Empty;
 
                foreach (var param in t.TypeParameters)
                {
                    if (typeParams.Length > 0)
                    {
                        typeParams += ",";
                    }
 
                    typeParams += param.Name;
                }
 
                elem.Add(new XAttribute("Of", typeParams));
            }
 
            if ((object)t.BaseType() != null)
            {
                elem.Add(new XAttribute("base", t.BaseType().ToTestDisplayString()));
            }
 
            var fields = t.GetMembers().Where(m => m.Kind == SymbolKind.Field).OrderBy(f => f.Name).Cast<FieldSymbol>();
 
            elem.Add(from f in fields select LoadField(f));
 
            var childrenTypes = t.GetTypeMembers().OrderBy(c => c, new NameAndArityComparer());
 
            elem.Add(from c in childrenTypes select LoadChildType(c));
 
            return elem;
        }
 
        private static XElement LoadField(FieldSymbol f)
        {
            XElement elem = new XElement("field");
 
            elem.Add(new XAttribute("name", f.Name));
            elem.Add(new XAttribute("type", f.Type.ToTestDisplayString()));
 
            return elem;
        }
 
        #region DeclSecurityTable Validation
        /// <summary>
        /// Validate the contents of the DeclSecurity metadata table.
        /// </summary>
        internal static void ValidateDeclSecurity(ModuleSymbol module, params DeclSecurityEntry[] expectedEntries)
        {
            var metadataReader = module.GetMetadata().MetadataReader;
            var actualEntries = new List<DeclSecurityEntry>(expectedEntries.Length);
 
            int i = 0;
            foreach (var actualHandle in metadataReader.DeclarativeSecurityAttributes)
            {
                var actual = metadataReader.GetDeclarativeSecurityAttribute(actualHandle);
 
                var actualPermissionSetBytes = metadataReader.GetBlobBytes(actual.PermissionSet);
                var actualPermissionSet = new string(actualPermissionSetBytes.Select(b => (char)b).ToArray());
                string actualParentName;
                SymbolKind actualParentKind;
                GetAttributeParentNameAndKind(metadataReader, actual.Parent, out actualParentName, out actualParentKind);
 
                actualEntries.Add(new DeclSecurityEntry()
                {
                    ActionFlags = actual.Action,
                    ParentNameOpt = actualParentName,
                    PermissionSet = actualPermissionSet,
                    ParentKind = actualParentKind
                });
 
                i++;
            }
 
            AssertEx.SetEqual(expectedEntries, actualEntries, itemInspector: entry => $@"
{{
    ActionFlags = {entry.ActionFlags},
    ParentNameOpt = {entry.ParentNameOpt},
    PermissionSet = {entry.PermissionSet},
    ParentKind = {entry.ParentKind}
}}");
        }
 
        private static void GetAttributeParentNameAndKind(MetadataReader metadataReader, EntityHandle token, out string name, out SymbolKind kind)
        {
            switch (token.Kind)
            {
                case HandleKind.AssemblyDefinition:
                    name = null;
                    kind = SymbolKind.Assembly;
                    return;
 
                case HandleKind.TypeDefinition:
                    name = metadataReader.GetString(metadataReader.GetTypeDefinition((TypeDefinitionHandle)token).Name);
                    kind = SymbolKind.NamedType;
                    return;
 
                case HandleKind.MethodDefinition:
                    name = metadataReader.GetString(metadataReader.GetMethodDefinition((MethodDefinitionHandle)token).Name);
                    kind = SymbolKind.Method;
                    return;
 
                default:
                    throw TestExceptionUtilities.UnexpectedValue(token.Kind);
            }
        }
 
        internal struct DeclSecurityEntry
        {
            public DeclarativeSecurityAction ActionFlags;
            public SymbolKind ParentKind;
            public string ParentNameOpt;
            public string PermissionSet;
        }
 
        #endregion
    }
}