File: Remote\RemoteHostClientServiceFactoryTests.cs
Web Access
Project: src\src\VisualStudio\Core\Test.Next\Roslyn.VisualStudio.Next.UnitTests.csproj (Roslyn.VisualStudio.Next.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.IO;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Options;
using Microsoft.CodeAnalysis.Remote.Testing;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.CodeAnalysis.SymbolSearch;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Remote.UnitTests
{
    [UseExportProvider]
    [Trait(Traits.Feature, Traits.Features.RemoteHost)]
    public class RemoteHostClientServiceFactoryTests
    {
        private static readonly TestComposition s_composition = FeaturesTestCompositions.Features.WithTestHostParts(TestHost.OutOfProcess);
 
        private static AdhocWorkspace CreateWorkspace()
            => new(s_composition.GetHostServices());
 
        [Fact]
        public async Task UpdaterService()
        {
            using var workspace = CreateWorkspace();
 
            var exportProvider = workspace.Services.SolutionServices.ExportProvider;
            var listenerProvider = exportProvider.GetExportedValue<AsynchronousOperationListenerProvider>();
            var globalOptions = exportProvider.GetExportedValue<IGlobalOptionService>();
 
            var checksumUpdater = new SolutionChecksumUpdater(workspace, listenerProvider, CancellationToken.None);
            var service = workspace.Services.GetRequiredService<IRemoteHostClientProvider>();
 
            // make sure client is ready
            using var client = await service.TryGetRemoteHostClientAsync(CancellationToken.None);
 
            // add solution, change document
            workspace.AddSolution(SolutionInfo.Create(SolutionId.CreateNewId(), VersionStamp.Default));
            var project = workspace.AddProject("proj", LanguageNames.CSharp);
            var document = workspace.AddDocument(project.Id, "doc.cs", SourceText.From("code"));
 
            var oldText = document.GetTextSynchronously(CancellationToken.None);
            var newText = oldText.WithChanges([new TextChange(new TextSpan(0, 1), "abc")]);
            var newSolution = document.Project.Solution.WithDocumentText(document.Id, newText, PreservationMode.PreserveIdentity);
 
            workspace.TryApplyChanges(newSolution);
 
            // wait for listener
            var workspaceListener = listenerProvider.GetWaiter(FeatureAttribute.Workspace);
            await workspaceListener.ExpeditedWaitAsync();
 
            var listener = listenerProvider.GetWaiter(FeatureAttribute.SolutionChecksumUpdater);
            await listener.ExpeditedWaitAsync();
 
            // checksum should already exist
            Assert.True(workspace.CurrentSolution.CompilationState.TryGetStateChecksums(out _));
 
            checksumUpdater.Shutdown();
        }
 
        [Fact]
        public async Task TestSessionWithNoSolution()
        {
            using var workspace = CreateWorkspace();
 
            var service = workspace.Services.GetRequiredService<IRemoteHostClientProvider>();
 
            var client = await service.TryGetRemoteHostClientAsync(CancellationToken.None);
 
            using var connection = client.CreateConnection<IRemoteSymbolSearchUpdateService>(callbackTarget: null);
            Assert.True(await connection.TryInvokeAsync(
                (service, cancellationToken) => service.UpdateContinuouslyAsync("emptySource", Path.GetTempPath(), cancellationToken),
                CancellationToken.None));
        }
 
        private class NullAssemblyAnalyzerLoader : IAnalyzerAssemblyLoader
        {
            public void AddDependencyLocation(string fullPath)
            {
            }
 
            public Assembly LoadFromPath(string fullPath)
            {
                // doesn't matter what it returns
                return typeof(object).Assembly;
            }
        }
    }
}