File: Cohost\BrokeredServiceFactory.cs
Web Access
Project: src\src\Razor\src\Razor\test\Microsoft.VisualStudio.LanguageServices.Razor.UnitTests\Microsoft.VisualStudio.LanguageServices.Razor.UnitTests.csproj (Microsoft.VisualStudio.LanguageServices.Razor.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.VisualStudio;
using Microsoft.CodeAnalysis.Razor.Logging;
using Microsoft.CodeAnalysis.Remote.Razor;
using Microsoft.ServiceHub.Framework;
using Microsoft.VisualStudio.Composition;
using Nerdbank.Streams;
using Xunit;
 
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
 
/// <summary>
///  Creates Razor brokered services.
/// </summary>
/// <remarks>
///  This class holds <see cref="RazorBrokeredServiceBase.FactoryBase{TService}"/> instances in a static
///  field. This should work fine in tests, since brokered service factories are intended to be stateless.
///  However, if a factory is introduced that maintains state, this class will need to be revisited to
///  avoid holding onto state across tests.
/// </remarks>
internal static class BrokeredServiceFactory
{
    private static readonly Dictionary<Type, IServiceHubServiceFactory> s_factoryMap = BuildFactoryMap();
 
    private static Dictionary<Type, IServiceHubServiceFactory> BuildFactoryMap()
    {
        var result = new Dictionary<Type, IServiceHubServiceFactory>();
 
        foreach (var type in typeof(RazorBrokeredServiceBase.FactoryBase<>).Assembly.GetTypes())
        {
            if (!type.IsAbstract &&
                typeof(IServiceHubServiceFactory).IsAssignableFrom(type))
            {
                Assert.Equal(typeof(RazorBrokeredServiceBase.FactoryBase<>), type.BaseType.GetGenericTypeDefinition());
 
                var genericType = type.BaseType.GetGenericArguments().Single();
 
                // ServiceHub requires a parameterless constructor, so we can safely rely on it existing too
                var factory = (IServiceHubServiceFactory)Activator.CreateInstance(type);
                result.Add(genericType, factory);
            }
        }
 
        return result;
    }
 
    public static async Task<TService> CreateServiceAsync<TService>(
        TestBrokeredServiceInterceptor brokeredServiceInterceptor, ExportProvider exportProvider, ILoggerFactory loggerFactory)
        where TService : class
    {
        Assert.True(s_factoryMap.TryGetValue(typeof(TService), out var factory));
 
        var (clientStream, serverStream) = FullDuplexStream.CreatePair();
        var brokeredServiceData = new RazorBrokeredServiceData(exportProvider, loggerFactory, brokeredServiceInterceptor, WorkspaceProvider: null);
        var hostProvidedServices = VsMocks.CreateServiceProvider(b =>
        {
            b.AddService(brokeredServiceData);
 
            // Don't provide a trace source. Brokered services and MEF components will rely on ILoggerFactory.
            b.AddService<TraceSource>((object?)null);
        });
 
        return (TService)await factory.CreateAsync(
            serverStream,
            hostProvidedServices,
            serviceActivationOptions: default,
            StrictMock.Of<IServiceBroker>(),
            authorizationServiceClient: default!);
    }
}