File: Assertions\AssemblyAssertions.cs
Web Access
Project: ..\..\..\test\Microsoft.NET.TestFramework\Microsoft.NET.TestFramework.csproj (Microsoft.NET.TestFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using FluentAssertions;
 
namespace Microsoft.NET.TestFramework.Assertions
{
    public class AssemblyAssertions
    {
        private FileInfo _assemblyPath;
 
        public AssemblyAssertions(FileInfo assemblyPath)
        {
            _assemblyPath = assemblyPath;
        }
 
        public FileInfo AssemblyPath => _assemblyPath;
 
        public AndConstraint<AssemblyAssertions> ContainType(string expectedType)
        {
            var types = GetDeclaredTypeNames();
 
            types.Should().Contain(expectedType, $"Expected type {expectedType} to be in assembly, but it is not.");
            return new AndConstraint<AssemblyAssertions>(this);
        }
 
        public AndConstraint<AssemblyAssertions> NotContainType(string expectedType)
        {
            var types = GetDeclaredTypeNames();
 
            types.Should().NotContain(expectedType, $"Expected type {expectedType} to not be in assembly, but it is.");
            return new AndConstraint<AssemblyAssertions>(this);
        }
 
        public AndConstraint<AssemblyAssertions> HaveAttribute(string expectedAttribute)
        {
            var attributes = GetAssemblyAttributes();
 
            attributes.Should().Contain(expectedAttribute, $"Expected attribute {expectedAttribute} to be in assembly, but it is not.");
            return new AndConstraint<AssemblyAssertions>(this);
        }
 
        private IEnumerable<string> GetDeclaredTypeNames()
        {
            using (var file = File.OpenRead(AssemblyPath.ToString()))
            {
                using var peReader = new PEReader(file);
                var metadataReader = peReader.GetMetadataReader();
                return metadataReader.TypeDefinitions.Where(t => !t.IsNil).Select(t =>
                {
                    var type = metadataReader.GetTypeDefinition(t);
                    return metadataReader.GetString(type.Namespace) + "." + metadataReader.GetString(type.Name);
                }).ToArray();
            }
        }
 
        private IEnumerable<string> GetAssemblyAttributes()
        {
            using (var file = File.OpenRead(AssemblyPath.ToString()))
            {
                var peReader = new PEReader(file);
                var metadataReader = peReader.GetMetadataReader();
                return metadataReader.CustomAttributes.Where(t => !t.IsNil).Select(t =>
                {
                    var attribute = metadataReader.GetCustomAttribute(t);
                    switch (attribute.Constructor.Kind)
                    {
                        case HandleKind.MethodDefinition:
                            {
                                var methodDef = metadataReader.GetMethodDefinition((MethodDefinitionHandle)attribute.Constructor);
                                var declaringTypeHandle = methodDef.GetDeclaringType();
                                var typeDefinition = metadataReader.GetTypeDefinition(declaringTypeHandle);
                                var @namespace = metadataReader.GetString(typeDefinition.Namespace);
                                var name = metadataReader.GetString(typeDefinition.Name);
                                return $"{@namespace}.{name}";
                            }
                        case HandleKind.MemberReference:
                            {
                                var memberRef = metadataReader.GetMemberReference((MemberReferenceHandle)attribute.Constructor);
                                var typeRef = metadataReader.GetTypeReference((TypeReferenceHandle)memberRef.Parent);
                                var @namespace = metadataReader.GetString(typeRef.Namespace);
                                var name = metadataReader.GetString(typeRef.Name);
                                return $"{@namespace}.{name}";
                            }
                        default:
                            throw new InvalidOperationException();
                    }
                }).ToArray();
            }
        }
    }
}