File: Workspaces\TestHostProject.cs
Web Access
Project: ..\..\..\src\EditorFeatures\TestUtilities\Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj (Microsoft.CodeAnalysis.EditorFeatures.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.IO;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Host;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
{
    public class TestHostProject
    {
        private readonly HostLanguageServices _languageServices;
 
        private readonly ProjectId _id;
        private readonly string _name;
        private readonly IEnumerable<MetadataReference> _metadataReferences;
        private readonly IEnumerable<AnalyzerReference> _analyzerReferences;
        private readonly CompilationOptions _compilationOptions;
        private readonly ParseOptions _parseOptions;
        private readonly bool _isSubmission;
        private readonly string _assemblyName;
        private readonly Type _hostObjectType;
        private readonly VersionStamp _version;
        private readonly string _outputFilePath;
        private readonly string _defaultNamespace;
 
        public IEnumerable<TestHostDocument> Documents;
        public IEnumerable<TestHostDocument> AdditionalDocuments;
        public IEnumerable<TestHostDocument> AnalyzerConfigDocuments;
        public IEnumerable<ProjectReference> ProjectReferences;
        private string _filePath;
 
        public string Name
        {
            get
            {
                return _name;
            }
        }
 
        public IEnumerable<MetadataReference> MetadataReferences
        {
            get
            {
                return _metadataReferences;
            }
        }
 
        public IEnumerable<AnalyzerReference> AnalyzerReferences
        {
            get
            {
                return _analyzerReferences;
            }
        }
 
        public CompilationOptions CompilationOptions
        {
            get
            {
                return _compilationOptions;
            }
        }
 
        public ParseOptions ParseOptions
        {
            get
            {
                return _parseOptions;
            }
        }
 
        public ProjectId Id
        {
            get
            {
                return _id;
            }
        }
 
        public bool IsSubmission
        {
            get
            {
                return _isSubmission;
            }
        }
 
        public string AssemblyName
        {
            get
            {
                return _assemblyName;
            }
        }
 
        public Type HostObjectType
        {
            get
            {
                return _hostObjectType;
            }
        }
 
        public VersionStamp Version
        {
            get
            {
                return _version;
            }
        }
 
        public string FilePath
        {
            get
            {
                return _filePath;
            }
        }
 
        internal void OnProjectFilePathChanged(string filePath)
            => _filePath = filePath;
 
        public string OutputFilePath
        {
            get { return _outputFilePath; }
        }
 
        public string DefaultNamespace
        {
            get { return _defaultNamespace; }
        }
 
        internal TestHostProject(
            HostLanguageServices languageServices,
            CompilationOptions compilationOptions,
            ParseOptions parseOptions,
            params MetadataReference[] references)
            : this(languageServices, compilationOptions, parseOptions, "Test", references)
        {
        }
        internal TestHostProject(
            HostLanguageServices languageServices,
            CompilationOptions compilationOptions,
            ParseOptions parseOptions,
            string assemblyName,
            params MetadataReference[] references)
            : this(languageServices,
                   compilationOptions,
                   parseOptions,
                   assemblyName: assemblyName,
                   projectName: assemblyName,
                   references: references,
                   documents: Array.Empty<TestHostDocument>())
        {
        }
 
        internal TestHostProject(
            HostLanguageServices languageServices,
            CompilationOptions compilationOptions,
            ParseOptions parseOptions,
            string assemblyName,
            string projectName,
            IList<MetadataReference> references,
            IList<TestHostDocument> documents,
            IList<TestHostDocument> additionalDocuments = null,
            IList<TestHostDocument> analyzerConfigDocuments = null,
            Type hostObjectType = null,
            bool isSubmission = false,
            string filePath = null,
            IList<AnalyzerReference> analyzerReferences = null,
            string defaultNamespace = null)
        {
            _assemblyName = assemblyName;
            _name = projectName;
            _id = ProjectId.CreateNewId(debugName: this.AssemblyName);
            _languageServices = languageServices;
            _compilationOptions = compilationOptions;
            _parseOptions = parseOptions;
            _metadataReferences = references;
            _analyzerReferences = analyzerReferences ?? SpecializedCollections.EmptyEnumerable<AnalyzerReference>();
            this.Documents = documents;
            this.AdditionalDocuments = additionalDocuments ?? SpecializedCollections.EmptyEnumerable<TestHostDocument>();
            this.AnalyzerConfigDocuments = analyzerConfigDocuments ?? SpecializedCollections.EmptyEnumerable<TestHostDocument>();
            ProjectReferences = SpecializedCollections.EmptyEnumerable<ProjectReference>();
            _isSubmission = isSubmission;
            _hostObjectType = hostObjectType;
            _version = VersionStamp.Create();
            _filePath = filePath;
            _outputFilePath = GetTestOutputFilePath(filePath);
            _defaultNamespace = defaultNamespace;
        }
 
        public TestHostProject(
            TestWorkspace workspace,
            TestHostDocument document,
            string name = null,
            string language = null,
            CompilationOptions compilationOptions = null,
            ParseOptions parseOptions = null,
            IEnumerable<TestHostProject> projectReferences = null,
            IEnumerable<MetadataReference> metadataReferences = null,
            IEnumerable<AnalyzerReference> analyzerReferences = null,
            string assemblyName = null,
            string defaultNamespace = null)
            : this(workspace, name, language, compilationOptions, parseOptions, SpecializedCollections.SingletonEnumerable(document), SpecializedCollections.EmptyEnumerable<TestHostDocument>(), SpecializedCollections.EmptyEnumerable<TestHostDocument>(), projectReferences, metadataReferences, analyzerReferences, assemblyName, defaultNamespace)
        {
        }
 
        public TestHostProject(
            TestWorkspace workspace,
            string name = null,
            string language = null,
            CompilationOptions compilationOptions = null,
            ParseOptions parseOptions = null,
            IEnumerable<TestHostDocument> documents = null,
            IEnumerable<TestHostDocument> additionalDocuments = null,
            IEnumerable<TestHostDocument> analyzerConfigDocuments = null,
            IEnumerable<TestHostProject> projectReferences = null,
            IEnumerable<MetadataReference> metadataReferences = null,
            IEnumerable<AnalyzerReference> analyzerReferences = null,
            string assemblyName = null,
            string defaultNamespace = null)
        {
            _name = name ?? "TestProject";
 
            _id = ProjectId.CreateNewId(debugName: this.Name);
 
            language = language ?? LanguageNames.CSharp;
            _languageServices = workspace.Services.GetLanguageServices(language);
 
            _compilationOptions = compilationOptions ?? this.LanguageServiceProvider.GetService<ICompilationFactoryService>().GetDefaultCompilationOptions();
            _parseOptions = parseOptions ?? this.LanguageServiceProvider.GetService<ISyntaxTreeFactoryService>().GetDefaultParseOptions();
            this.Documents = documents ?? SpecializedCollections.EmptyEnumerable<TestHostDocument>();
            this.AdditionalDocuments = additionalDocuments ?? SpecializedCollections.EmptyEnumerable<TestHostDocument>();
            this.AnalyzerConfigDocuments = analyzerConfigDocuments ?? SpecializedCollections.EmptyEnumerable<TestHostDocument>();
            ProjectReferences = projectReferences != null ? projectReferences.Select(p => new ProjectReference(p.Id)) : SpecializedCollections.EmptyEnumerable<ProjectReference>();
            _metadataReferences = metadataReferences ?? new MetadataReference[] { TestMetadata.Net451.mscorlib };
            _analyzerReferences = analyzerReferences ?? SpecializedCollections.EmptyEnumerable<AnalyzerReference>();
            _assemblyName = assemblyName ?? "TestProject";
            _version = VersionStamp.Create();
            _outputFilePath = GetTestOutputFilePath(_filePath);
            _defaultNamespace = defaultNamespace;
 
            if (documents != null)
            {
                foreach (var doc in documents)
                {
                    doc.SetProject(this);
                }
            }
 
            if (additionalDocuments != null)
            {
                foreach (var doc in additionalDocuments)
                {
                    doc.SetProject(this);
                }
            }
 
            if (analyzerConfigDocuments != null)
            {
                foreach (var doc in analyzerConfigDocuments)
                {
                    doc.SetProject(this);
                }
            }
        }
 
        internal void SetSolution(TestHostSolution _)
        {
            // set up back pointer to this project.
            if (this.Documents != null)
            {
                foreach (var doc in this.Documents)
                {
                    doc.SetProject(this);
                }
 
                foreach (var doc in this.AdditionalDocuments)
                {
                    doc.SetProject(this);
                }
 
                foreach (var doc in this.AnalyzerConfigDocuments)
                {
                    doc.SetProject(this);
                }
            }
        }
 
        internal void AddDocument(TestHostDocument document)
        {
            this.Documents = this.Documents.Concat(new TestHostDocument[] { document });
            document.SetProject(this);
        }
 
        internal void RemoveDocument(TestHostDocument document)
            => this.Documents = this.Documents.Where(d => d != document);
 
        internal void AddAdditionalDocument(TestHostDocument document)
        {
            this.AdditionalDocuments = this.AdditionalDocuments.Concat(new TestHostDocument[] { document });
            document.SetProject(this);
        }
 
        internal void RemoveAdditionalDocument(TestHostDocument document)
            => this.AdditionalDocuments = this.AdditionalDocuments.Where(d => d != document);
 
        internal void AddAnalyzerConfigDocument(TestHostDocument document)
        {
            this.AnalyzerConfigDocuments = this.AnalyzerConfigDocuments.Concat(new TestHostDocument[] { document });
            document.SetProject(this);
        }
 
        internal void RemoveAnalyzerConfigDocument(TestHostDocument document)
            => this.AnalyzerConfigDocuments = this.AnalyzerConfigDocuments.Where(d => d != document);
 
        public string Language
        {
            get
            {
                return _languageServices.Language;
            }
        }
 
        internal HostLanguageServices LanguageServiceProvider
        {
            get
            {
                return _languageServices;
            }
        }
 
        public ProjectInfo ToProjectInfo()
        {
            return ProjectInfo.Create(
                new ProjectInfo.ProjectAttributes(
                    Id,
                    Version,
                    name: Name,
                    assemblyName: AssemblyName,
                    language: Language,
                    compilationOutputFilePaths: default,
                    checksumAlgorithm: Text.SourceHashAlgorithms.Default,
                    defaultNamespace: DefaultNamespace,
                    filePath: FilePath,
                    outputFilePath: OutputFilePath,
                    isSubmission: IsSubmission),
                CompilationOptions,
                ParseOptions,
                documents: Documents.Where(d => !d.IsSourceGenerated).Select(d => d.ToDocumentInfo()),
                ProjectReferences,
                MetadataReferences,
                AnalyzerReferences,
                additionalDocuments: AdditionalDocuments.Select(d => d.ToDocumentInfo()),
                analyzerConfigDocuments: AnalyzerConfigDocuments.Select(d => d.ToDocumentInfo()),
                HostObjectType);
        }
 
        // It is identical with the internal extension method 'GetDefaultExtension' defined in OutputKind.cs.
        // However, we could not apply for InternalVisibleToTest due to other parts of this assembly
        // complaining about CS0507: "cannot change access modifiers when overriding 'access' inherited member".
        private static string GetDefaultExtension(OutputKind kind)
        {
            switch (kind)
            {
                case OutputKind.ConsoleApplication:
                case OutputKind.WindowsApplication:
                case OutputKind.WindowsRuntimeApplication:
                    return ".exe";
 
                case OutputKind.DynamicallyLinkedLibrary:
                    return ".dll";
 
                case OutputKind.NetModule:
                    return ".netmodule";
 
                case OutputKind.WindowsRuntimeMetadata:
                    return ".winmdobj";
 
                default:
                    return ".dll";
            }
        }
 
        private string GetTestOutputFilePath(string filepath)
        {
            var outputFilePath = @"Z:\";
 
            try
            {
                outputFilePath = Path.GetDirectoryName(filepath);
            }
            catch (ArgumentException)
            {
            }
 
            if (string.IsNullOrEmpty(outputFilePath))
            {
                outputFilePath = @"Z:\";
            }
 
            return this.CompilationOptions == null ? "" : Path.Combine(outputFilePath, this.AssemblyName + GetDefaultExtension(this.CompilationOptions.OutputKind));
        }
    }
}