diff --git a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs index 76bfbf33feed5..f22969086ec14 100644 --- a/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs +++ b/src/VisualStudio/Core/Test.Next/Services/VisualStudioDiagnosticAnalyzerExecutorTests.cs @@ -154,7 +154,7 @@ public async Task TestCancellationOnSessionWithSolution() Assert.Equal(exception.CancellationToken, source.Token); // make sure things that should have been cleaned up are cleaned up - Assert.Null(await ((RemotableDataServiceFactory.Service)service).TestOnly_GetRemotableDataAsync(solutionChecksum, CancellationToken.None).ConfigureAwait(false)); + Assert.Null(await ((RemotableDataService)service).TestOnly_GetRemotableDataAsync(solutionChecksum, CancellationToken.None).ConfigureAwait(false)); } } diff --git a/src/Workspaces/Core/Portable/Execution/RemotableDataService.cs b/src/Workspaces/Core/Portable/Execution/RemotableDataService.cs new file mode 100644 index 0000000000000..6903a360e0b47 --- /dev/null +++ b/src/Workspaces/Core/Portable/Execution/RemotableDataService.cs @@ -0,0 +1,72 @@ +// 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 enable + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Host.Mef; +using Microsoft.CodeAnalysis.Internal.Log; + +namespace Microsoft.CodeAnalysis.Execution +{ + internal sealed class RemotableDataService : IRemotableDataService + { + [ExportWorkspaceServiceFactory(typeof(IRemotableDataService)), Shared] + internal sealed class Factory : IWorkspaceServiceFactory + { + private readonly AssetStorages _assetStorages = new AssetStorages(); + + [ImportingConstructor] + [Obsolete(MefConstruction.ImportingConstructorMessage, error: true)] + public Factory() + { + } + + public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) + => new RemotableDataService(_assetStorages); + } + + private readonly AssetStorages _assetStorages; + + private RemotableDataService(AssetStorages storages) + { + _assetStorages = storages; + } + + public async ValueTask CreatePinnedRemotableDataScopeAsync(Solution solution, CancellationToken cancellationToken) + { + using (Logger.LogBlock(FunctionId.SolutionSynchronizationServiceFactory_CreatePinnedRemotableDataScopeAsync, cancellationToken)) + { + var storage = AssetStorages.CreateStorage(solution.State); + var checksum = await solution.State.GetChecksumAsync(cancellationToken).ConfigureAwait(false); + + return PinnedRemotableDataScope.Create(_assetStorages, storage, checksum); + } + } + + public async ValueTask GetRemotableDataAsync(int scopeId, Checksum checksum, CancellationToken cancellationToken) + { + using (Logger.LogBlock(FunctionId.SolutionSynchronizationService_GetRemotableData, Checksum.GetChecksumLogInfo, checksum, cancellationToken)) + { + return await _assetStorages.GetRemotableDataAsync(scopeId, checksum, cancellationToken).ConfigureAwait(false); + } + } + + public async ValueTask> GetRemotableDataAsync(int scopeId, IEnumerable checksums, CancellationToken cancellationToken) + { + using (Logger.LogBlock(FunctionId.SolutionSynchronizationService_GetRemotableData, Checksum.GetChecksumsLogInfo, checksums, cancellationToken)) + { + return await _assetStorages.GetRemotableDataAsync(scopeId, checksums, cancellationToken).ConfigureAwait(false); + } + } + + public async ValueTask TestOnly_GetRemotableDataAsync(Checksum checksum, CancellationToken cancellationToken) + => await _assetStorages.TestOnly_GetRemotableDataAsync(checksum, cancellationToken).ConfigureAwait(false); + } +} diff --git a/src/Workspaces/Core/Portable/Execution/SolutionSynchronizationService.cs b/src/Workspaces/Core/Portable/Execution/SolutionSynchronizationService.cs deleted file mode 100644 index 86c3f3e15fbf9..0000000000000 --- a/src/Workspaces/Core/Portable/Execution/SolutionSynchronizationService.cs +++ /dev/null @@ -1,77 +0,0 @@ -// 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 enable - -using System.Collections.Generic; -using System.Composition; -using System.Diagnostics.CodeAnalysis; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Host.Mef; -using Microsoft.CodeAnalysis.Internal.Log; -using Microsoft.CodeAnalysis.Serialization; - -namespace Microsoft.CodeAnalysis.Execution -{ - [ExportWorkspaceServiceFactory(typeof(IRemotableDataService)), Shared] - internal class RemotableDataServiceFactory : IWorkspaceServiceFactory - { - private readonly AssetStorages _assetStorages = new AssetStorages(); - - [ImportingConstructor] - [SuppressMessage("RoslynDiagnosticsReliability", "RS0033:Importing constructor should be [Obsolete]", Justification = "Used in test code: https://github.com/dotnet/roslyn/issues/42814")] - public RemotableDataServiceFactory() - { - } - - public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices) - => new Service(workspaceServices, _assetStorages); - - internal class Service : IRemotableDataService - { - private readonly HostWorkspaceServices _workspaceServices; - private readonly AssetStorages _assetStorages; - - public ISerializerService Serializer_TestOnly => _workspaceServices.GetRequiredService(); - - public Service(HostWorkspaceServices workspaceServices, AssetStorages storages) - { - _workspaceServices = workspaceServices; - _assetStorages = storages; - } - - public async ValueTask CreatePinnedRemotableDataScopeAsync(Solution solution, CancellationToken cancellationToken) - { - using (Logger.LogBlock(FunctionId.SolutionSynchronizationServiceFactory_CreatePinnedRemotableDataScopeAsync, cancellationToken)) - { - var storage = AssetStorages.CreateStorage(solution.State); - var checksum = await solution.State.GetChecksumAsync(cancellationToken).ConfigureAwait(false); - - return PinnedRemotableDataScope.Create(_assetStorages, storage, checksum); - } - } - - public async ValueTask GetRemotableDataAsync(int scopeId, Checksum checksum, CancellationToken cancellationToken) - { - using (Logger.LogBlock(FunctionId.SolutionSynchronizationService_GetRemotableData, Checksum.GetChecksumLogInfo, checksum, cancellationToken)) - { - return await _assetStorages.GetRemotableDataAsync(scopeId, checksum, cancellationToken).ConfigureAwait(false); - } - } - - public async ValueTask> GetRemotableDataAsync(int scopeId, IEnumerable checksums, CancellationToken cancellationToken) - { - using (Logger.LogBlock(FunctionId.SolutionSynchronizationService_GetRemotableData, Checksum.GetChecksumsLogInfo, checksums, cancellationToken)) - { - return await _assetStorages.GetRemotableDataAsync(scopeId, checksums, cancellationToken).ConfigureAwait(false); - } - } - - public async ValueTask TestOnly_GetRemotableDataAsync(Checksum checksum, CancellationToken cancellationToken) - => await _assetStorages.TestOnly_GetRemotableDataAsync(checksum, cancellationToken).ConfigureAwait(false); - } - } -} diff --git a/src/Workspaces/CoreTest/Execution/SnapshotSerializationTests.cs b/src/Workspaces/CoreTest/Execution/SnapshotSerializationTests.cs index dbb933383f8dc..01082a5d5074c 100644 --- a/src/Workspaces/CoreTest/Execution/SnapshotSerializationTests.cs +++ b/src/Workspaces/CoreTest/Execution/SnapshotSerializationTests.cs @@ -18,35 +18,69 @@ using Microsoft.CodeAnalysis.Host.Mef; using Microsoft.CodeAnalysis.Options; using Microsoft.CodeAnalysis.Serialization; +using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.UnitTests.Execution; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.UnitTests { - public class SnapshotSerializationTests : SnapshotSerializationTestBase + [UseExportProvider] + public class SnapshotSerializationTests { + internal static Solution CreateFullSolution(Workspace workspace) + { + var solution = workspace.CurrentSolution; + var languages = ImmutableHashSet.Create(LanguageNames.CSharp, LanguageNames.VisualBasic); + var solutionOptions = solution.Workspace.Services.GetRequiredService().GetSerializableOptionsSnapshot(languages); + solution = solution.WithOptions(solutionOptions); + + var csCode = "class A { }"; + var project1 = solution.AddProject("Project", "Project.dll", LanguageNames.CSharp); + var document1 = project1.AddDocument("Document1", SourceText.From(csCode)); + + var vbCode = "Class B\r\nEnd Class"; + var project2 = document1.Project.Solution.AddProject("Project2", "Project2.dll", LanguageNames.VisualBasic); + var document2 = project2.AddDocument("Document2", SourceText.From(vbCode)); + + solution = document2.Project.Solution.GetRequiredProject(project1.Id) + .AddProjectReference(new ProjectReference(project2.Id, ImmutableArray.Create("test"))) + .AddMetadataReference(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)) + .AddAnalyzerReference(new AnalyzerFileReference(Path.Combine(TempRoot.Root, "path1"), new TestAnalyzerAssemblyLoader())) + .AddAdditionalDocument("Additional", SourceText.From("hello"), ImmutableArray.Create("test"), @".\Add").Project.Solution; + + return solution + .WithAnalyzerReferences(new[] { new AnalyzerFileReference(Path.Combine(TempRoot.Root, "path2"), new TestAnalyzerAssemblyLoader()) }) + .AddAnalyzerConfigDocuments( + ImmutableArray.Create( + DocumentInfo.Create( + DocumentId.CreateNewId(project1.Id), + ".editorconfig", + loader: TextLoader.From(TextAndVersion.Create(SourceText.From("root = true"), VersionStamp.Create()))))); + } + [Fact] public async Task CreateSolutionSnapshotId_Empty() { - var solution = new AdhocWorkspace().CurrentSolution; + using var workspace = new AdhocWorkspace(); + var solution = workspace.CurrentSolution; + + var validator = new SerializationValidator(workspace.Services); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); var checksum = snapshot.SolutionChecksum; var solutionSyncObject = await snapshot.GetRemotableDataAsync(checksum, CancellationToken.None).ConfigureAwait(false); - await VerifySynchronizationObjectInServiceAsync(snapshotService, solutionSyncObject).ConfigureAwait(false); + await validator.VerifySynchronizationObjectInServiceAsync(solutionSyncObject).ConfigureAwait(false); - var solutionObject = await snapshotService.GetValueAsync(checksum).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Options, WellKnownSynchronizationKind.OptionSet).ConfigureAwait(false); + var solutionObject = await validator.GetValueAsync(checksum).ConfigureAwait(false); + await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes).ConfigureAwait(false); + await validator.VerifyChecksumInServiceAsync(solutionObject.Options, WellKnownSynchronizationKind.OptionSet).ConfigureAwait(false); var projectsSyncObject = await snapshot.GetRemotableDataAsync(solutionObject.Projects.Checksum, CancellationToken.None).ConfigureAwait(false); - await VerifySynchronizationObjectInServiceAsync(snapshotService, projectsSyncObject).ConfigureAwait(false); + await validator.VerifySynchronizationObjectInServiceAsync(projectsSyncObject).ConfigureAwait(false); Assert.Equal(0, solutionObject.Projects.Count); } @@ -54,45 +88,51 @@ public async Task CreateSolutionSnapshotId_Empty() [Fact] public async Task CreateSolutionSnapshotId_Empty_Serialization() { - var solution = new AdhocWorkspace().CurrentSolution; + using var workspace = new AdhocWorkspace(); + var solution = workspace.CurrentSolution; - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); - await VerifySolutionStateSerializationAsync(snapshotService, solution, snapshot.SolutionChecksum).ConfigureAwait(false); + var validator = new SerializationValidator(workspace.Services); + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); + await validator.VerifySolutionStateSerializationAsync(solution, snapshot.SolutionChecksum).ConfigureAwait(false); } [Fact] public async Task CreateSolutionSnapshotId_Project() { - var project = new AdhocWorkspace().CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); + using var workspace = new AdhocWorkspace(); + var solution = workspace.CurrentSolution; + var project = solution.AddProject("Project", "Project.dll", LanguageNames.CSharp); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(project.Solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); + var validator = new SerializationValidator(workspace.Services); + + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); var checksum = snapshot.SolutionChecksum; var solutionSyncObject = await snapshot.GetRemotableDataAsync(checksum, CancellationToken.None).ConfigureAwait(false); - await VerifySynchronizationObjectInServiceAsync(snapshotService, solutionSyncObject).ConfigureAwait(false); + await validator.VerifySynchronizationObjectInServiceAsync(solutionSyncObject).ConfigureAwait(false); - var solutionObject = await snapshotService.GetValueAsync(checksum).ConfigureAwait(false); + var solutionObject = await validator.GetValueAsync(checksum).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Options, WellKnownSynchronizationKind.OptionSet); + await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes); + await validator.VerifyChecksumInServiceAsync(solutionObject.Options, WellKnownSynchronizationKind.OptionSet); var projectSyncObject = await snapshot.GetRemotableDataAsync(solutionObject.Projects.Checksum, CancellationToken.None).ConfigureAwait(false); - await VerifySynchronizationObjectInServiceAsync(snapshotService, projectSyncObject).ConfigureAwait(false); + await validator.VerifySynchronizationObjectInServiceAsync(projectSyncObject).ConfigureAwait(false); Assert.Equal(1, solutionObject.Projects.Count); - await VerifySnapshotInServiceAsync(snapshotService, solutionObject.Projects.ToProjectObjects(snapshotService)[0], 0, 0, 0, 0, 0).ConfigureAwait(false); + await validator.VerifySnapshotInServiceAsync(validator.ToProjectObjects(solutionObject.Projects)[0], 0, 0, 0, 0, 0).ConfigureAwait(false); } [Fact] public async Task CreateSolutionSnapshotId_Project_Serialization() { - var project = new AdhocWorkspace().CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); + using var workspace = new AdhocWorkspace(); + var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); + + var validator = new SerializationValidator(workspace.Services); - var snapshotService = (new RemotableDataServiceFactory()).CreateService(project.Solution.Workspace.Services) as IRemotableDataService; - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); - await VerifySolutionStateSerializationAsync(snapshotService, project.Solution, snapshot.SolutionChecksum).ConfigureAwait(false); + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); + await validator.VerifySolutionStateSerializationAsync(project.Solution, snapshot.SolutionChecksum).ConfigureAwait(false); } [Fact] @@ -100,20 +140,22 @@ public async Task CreateSolutionSnapshotId() { var code = "class A { }"; - var document = new AdhocWorkspace().CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp).AddDocument("Document", SourceText.From(code)); + using var workspace = new AdhocWorkspace(); + var document = workspace.CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp).AddDocument("Document", SourceText.From(code)); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(document.Project.Solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(document.Project.Solution, CancellationToken.None).ConfigureAwait(false); + var validator = new SerializationValidator(workspace.Services); + + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(document.Project.Solution, CancellationToken.None).ConfigureAwait(false); var syncObject = await snapshot.GetRemotableDataAsync(snapshot.SolutionChecksum, CancellationToken.None).ConfigureAwait(false); - var solutionObject = await snapshotService.GetValueAsync(syncObject.Checksum).ConfigureAwait(false); + var solutionObject = await validator.GetValueAsync(syncObject.Checksum).ConfigureAwait(false); - await VerifySynchronizationObjectInServiceAsync(snapshotService, syncObject).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Options, WellKnownSynchronizationKind.OptionSet).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Projects.Checksum, WellKnownSynchronizationKind.Projects).ConfigureAwait(false); + await validator.VerifySynchronizationObjectInServiceAsync(syncObject).ConfigureAwait(false); + await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes).ConfigureAwait(false); + await validator.VerifyChecksumInServiceAsync(solutionObject.Options, WellKnownSynchronizationKind.OptionSet).ConfigureAwait(false); + await validator.VerifyChecksumInServiceAsync(solutionObject.Projects.Checksum, WellKnownSynchronizationKind.Projects).ConfigureAwait(false); Assert.Equal(1, solutionObject.Projects.Count); - await VerifySnapshotInServiceAsync(snapshotService, solutionObject.Projects.ToProjectObjects(snapshotService)[0], 1, 0, 0, 0, 0).ConfigureAwait(false); + await validator.VerifySnapshotInServiceAsync(validator.ToProjectObjects(solutionObject.Projects)[0], 1, 0, 0, 0, 0).ConfigureAwait(false); } [Fact] @@ -121,97 +163,110 @@ public async Task CreateSolutionSnapshotId_Serialization() { var code = "class A { }"; - var document = new AdhocWorkspace().CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp).AddDocument("Document", SourceText.From(code)); + using var workspace = new AdhocWorkspace(); + var solution = workspace.CurrentSolution; + var document = solution.AddProject("Project", "Project.dll", LanguageNames.CSharp).AddDocument("Document", SourceText.From(code)); + + var validator = new SerializationValidator(workspace.Services); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(document.Project.Solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(document.Project.Solution, CancellationToken.None).ConfigureAwait(false); - await VerifySolutionStateSerializationAsync(snapshotService, document.Project.Solution, snapshot.SolutionChecksum).ConfigureAwait(false); + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(document.Project.Solution, CancellationToken.None).ConfigureAwait(false); + await validator.VerifySolutionStateSerializationAsync(document.Project.Solution, snapshot.SolutionChecksum).ConfigureAwait(false); } [Fact] public async Task CreateSolutionSnapshotId_Full() { - var solution = CreateFullSolution(); + using var workspace = new AdhocWorkspace(); + var solution = CreateFullSolution(workspace); var firstProjectChecksum = await solution.GetProject(solution.ProjectIds[0]).State.GetChecksumAsync(CancellationToken.None); var secondProjectChecksum = await solution.GetProject(solution.ProjectIds[1]).State.GetChecksumAsync(CancellationToken.None); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); + var validator = new SerializationValidator(workspace.Services); + + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); var syncObject = await snapshot.GetRemotableDataAsync(snapshot.SolutionChecksum, CancellationToken.None).ConfigureAwait(false); - var solutionObject = await snapshotService.GetValueAsync(syncObject.Checksum).ConfigureAwait(false); + var solutionObject = await validator.GetValueAsync(syncObject.Checksum).ConfigureAwait(false); - await VerifySynchronizationObjectInServiceAsync(snapshotService, syncObject).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Options, WellKnownSynchronizationKind.OptionSet).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Projects.Checksum, WellKnownSynchronizationKind.Projects).ConfigureAwait(false); + await validator.VerifySynchronizationObjectInServiceAsync(syncObject).ConfigureAwait(false); + await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes).ConfigureAwait(false); + await validator.VerifyChecksumInServiceAsync(solutionObject.Options, WellKnownSynchronizationKind.OptionSet).ConfigureAwait(false); + await validator.VerifyChecksumInServiceAsync(solutionObject.Projects.Checksum, WellKnownSynchronizationKind.Projects).ConfigureAwait(false); Assert.Equal(2, solutionObject.Projects.Count); - var projects = solutionObject.Projects.ToProjectObjects(snapshotService); - await VerifySnapshotInServiceAsync(snapshotService, projects.Where(p => p.Checksum == firstProjectChecksum).First(), 1, 1, 1, 1, 1).ConfigureAwait(false); - await VerifySnapshotInServiceAsync(snapshotService, projects.Where(p => p.Checksum == secondProjectChecksum).First(), 1, 0, 0, 0, 0).ConfigureAwait(false); + var projects = validator.ToProjectObjects(solutionObject.Projects); + await validator.VerifySnapshotInServiceAsync(projects.Where(p => p.Checksum == firstProjectChecksum).First(), 1, 1, 1, 1, 1).ConfigureAwait(false); + await validator.VerifySnapshotInServiceAsync(projects.Where(p => p.Checksum == secondProjectChecksum).First(), 1, 0, 0, 0, 0).ConfigureAwait(false); } [Fact] public async Task CreateSolutionSnapshotId_Full_Serialization() { - var solution = CreateFullSolution(); + using var workspace = new AdhocWorkspace(); + var solution = CreateFullSolution(workspace); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); - await VerifySolutionStateSerializationAsync(snapshotService, solution, snapshot.SolutionChecksum).ConfigureAwait(false); + var validator = new SerializationValidator(workspace.Services); + + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); + await validator.VerifySolutionStateSerializationAsync(solution, snapshot.SolutionChecksum).ConfigureAwait(false); } [Fact] public async Task CreateSolutionSnapshotId_Full_Asset_Serialization() { - var solution = CreateFullSolution(); + using var workspace = new AdhocWorkspace(); + var solution = CreateFullSolution(workspace); + + var validator = new SerializationValidator(workspace.Services); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); - var solutionObject = await snapshotService.GetValueAsync(snapshot.SolutionChecksum); - await VerifyAssetAsync(snapshotService, solutionObject).ConfigureAwait(false); + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); + var solutionObject = await validator.GetValueAsync(snapshot.SolutionChecksum); + await validator.VerifyAssetAsync(solutionObject).ConfigureAwait(false); } [Fact] public async Task CreateSolutionSnapshotId_Full_Asset_Serialization_Desktop() { var hostServices = MefHostServices.Create( - MefHostServices.DefaultAssemblies.Add(typeof(Host.TemporaryStorageServiceFactory.TemporaryStorageService).Assembly)); + MefHostServices.DefaultAssemblies.Add(typeof(TemporaryStorageServiceFactory.TemporaryStorageService).Assembly)); + + using var workspace = new AdhocWorkspace(hostServices); + var solution = CreateFullSolution(workspace); - var solution = CreateFullSolution(hostServices); + var validator = new SerializationValidator(workspace.Services); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); - var solutionObject = await snapshotService.GetValueAsync(snapshot.SolutionChecksum); - await VerifyAssetAsync(snapshotService, solutionObject).ConfigureAwait(false); + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); + var solutionObject = await validator.GetValueAsync(snapshot.SolutionChecksum); + await validator.VerifyAssetAsync(solutionObject).ConfigureAwait(false); } [Fact] public async Task CreateSolutionSnapshotId_Duplicate() { - var solution = CreateFullSolution(); + using var workspace = new AdhocWorkspace(); + var solution = CreateFullSolution(workspace); // this is just data, one can hold the id outside of using statement. but // one can't get asset using checksum from the id. SolutionStateChecksums solutionId1; SolutionStateChecksums solutionId2; - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using (var snapshot1 = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false)) + var validator = new SerializationValidator(workspace.Services); + + using (var snapshot1 = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false)) { - solutionId1 = await snapshotService.GetValueAsync(snapshot1.SolutionChecksum).ConfigureAwait(false); + solutionId1 = await validator.GetValueAsync(snapshot1.SolutionChecksum).ConfigureAwait(false); } - using (var snapshot2 = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false)) + using (var snapshot2 = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false)) { - solutionId2 = await snapshotService.GetValueAsync(snapshot2.SolutionChecksum).ConfigureAwait(false); + solutionId2 = await validator.GetValueAsync(snapshot2.SolutionChecksum).ConfigureAwait(false); } // once pinned snapshot scope is released, there is no way to get back to asset. // catch Exception because it will throw 2 different exception based on release or debug (ExceptionUtilities.UnexpectedValue) - Assert.ThrowsAny(() => SolutionStateEqual(snapshotService, solutionId1, solutionId2)); + Assert.ThrowsAny(() => validator.SolutionStateEqual(solutionId1, solutionId2)); } [Fact] @@ -233,37 +288,39 @@ public async Task MetadataReference_RoundTrip_Test() [Fact] public async Task Workspace_RoundTrip_Test() { - var solution = CreateFullSolution(); + using var workspace = new AdhocWorkspace(); + var solution = CreateFullSolution(workspace); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using var snapshot1 = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); + var validator = new SerializationValidator(workspace.Services); + + using var snapshot1 = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); // recover solution from given snapshot - var recovered = await GetSolutionAsync(snapshotService, snapshot1).ConfigureAwait(false); - var solutionObject1 = await snapshotService.GetValueAsync(snapshot1.SolutionChecksum).ConfigureAwait(false); + var recovered = await validator.GetSolutionAsync(snapshot1).ConfigureAwait(false); + var solutionObject1 = await validator.GetValueAsync(snapshot1.SolutionChecksum).ConfigureAwait(false); // create new snapshot from recovered solution - using var snapshot2 = await snapshotService.CreatePinnedRemotableDataScopeAsync(recovered, CancellationToken.None).ConfigureAwait(false); + using var snapshot2 = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(recovered, CancellationToken.None).ConfigureAwait(false); // verify asset created by recovered solution is good - var solutionObject2 = await snapshotService.GetValueAsync(snapshot2.SolutionChecksum).ConfigureAwait(false); - await VerifyAssetAsync(snapshotService, solutionObject2).ConfigureAwait(false); + var solutionObject2 = await validator.GetValueAsync(snapshot2.SolutionChecksum).ConfigureAwait(false); + await validator.VerifyAssetAsync(solutionObject2).ConfigureAwait(false); // verify snapshots created from original solution and recovered solution are same - SolutionStateEqual(snapshotService, solutionObject1, solutionObject2); + validator.SolutionStateEqual(solutionObject1, solutionObject2); snapshot1.Dispose(); // recover new solution from recovered solution - var roundtrip = await GetSolutionAsync(snapshotService, snapshot2).ConfigureAwait(false); + var roundtrip = await validator.GetSolutionAsync(snapshot2).ConfigureAwait(false); // create new snapshot from round tripped solution - using var snapshot3 = await snapshotService.CreatePinnedRemotableDataScopeAsync(roundtrip, CancellationToken.None).ConfigureAwait(false); + using var snapshot3 = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(roundtrip, CancellationToken.None).ConfigureAwait(false); // verify asset created by rount trip solution is good - var solutionObject3 = await snapshotService.GetValueAsync(snapshot3.SolutionChecksum).ConfigureAwait(false); - await VerifyAssetAsync(snapshotService, solutionObject3).ConfigureAwait(false); + var solutionObject3 = await validator.GetValueAsync(snapshot3.SolutionChecksum).ConfigureAwait(false); + await validator.VerifyAssetAsync(solutionObject3).ConfigureAwait(false); // verify snapshots created from original solution and round trip solution are same. - SolutionStateEqual(snapshotService, solutionObject2, solutionObject3); + validator.SolutionStateEqual(solutionObject2, solutionObject3); snapshot2.Dispose(); } @@ -271,39 +328,41 @@ public async Task Workspace_RoundTrip_Test() public async Task Workspace_RoundTrip_Test_Desktop() { var hostServices = MefHostServices.Create( - MefHostServices.DefaultAssemblies.Add(typeof(Host.TemporaryStorageServiceFactory.TemporaryStorageService).Assembly)); + MefHostServices.DefaultAssemblies.Add(typeof(TemporaryStorageServiceFactory.TemporaryStorageService).Assembly)); - var solution = CreateFullSolution(hostServices); + using var workspace = new AdhocWorkspace(hostServices); + var solution = CreateFullSolution(workspace); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using var snapshot1 = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); + var validator = new SerializationValidator(workspace.Services); + + using var snapshot1 = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None).ConfigureAwait(false); // recover solution from given snapshot - var recovered = await GetSolutionAsync(snapshotService, snapshot1).ConfigureAwait(false); - var solutionObject1 = await snapshotService.GetValueAsync(snapshot1.SolutionChecksum).ConfigureAwait(false); + var recovered = await validator.GetSolutionAsync(snapshot1).ConfigureAwait(false); + var solutionObject1 = await validator.GetValueAsync(snapshot1.SolutionChecksum).ConfigureAwait(false); // create new snapshot from recovered solution - using var snapshot2 = await snapshotService.CreatePinnedRemotableDataScopeAsync(recovered, CancellationToken.None).ConfigureAwait(false); + using var snapshot2 = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(recovered, CancellationToken.None).ConfigureAwait(false); // verify asset created by recovered solution is good - var solutionObject2 = await snapshotService.GetValueAsync(snapshot2.SolutionChecksum).ConfigureAwait(false); - await VerifyAssetAsync(snapshotService, solutionObject2).ConfigureAwait(false); + var solutionObject2 = await validator.GetValueAsync(snapshot2.SolutionChecksum).ConfigureAwait(false); + await validator.VerifyAssetAsync(solutionObject2).ConfigureAwait(false); // verify snapshots created from original solution and recovered solution are same - SolutionStateEqual(snapshotService, solutionObject1, solutionObject2); + validator.SolutionStateEqual(solutionObject1, solutionObject2); snapshot1.Dispose(); // recover new solution from recovered solution - var roundtrip = await GetSolutionAsync(snapshotService, snapshot2).ConfigureAwait(false); + var roundtrip = await validator.GetSolutionAsync(snapshot2).ConfigureAwait(false); // create new snapshot from round tripped solution - using var snapshot3 = await snapshotService.CreatePinnedRemotableDataScopeAsync(roundtrip, CancellationToken.None).ConfigureAwait(false); + using var snapshot3 = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(roundtrip, CancellationToken.None).ConfigureAwait(false); // verify asset created by rount trip solution is good - var solutionObject3 = await snapshotService.GetValueAsync(snapshot3.SolutionChecksum).ConfigureAwait(false); - await VerifyAssetAsync(snapshotService, solutionObject3).ConfigureAwait(false); + var solutionObject3 = await validator.GetValueAsync(snapshot3.SolutionChecksum).ConfigureAwait(false); + await validator.VerifyAssetAsync(solutionObject3).ConfigureAwait(false); // verify snapshots created from original solution and round trip solution are same. - SolutionStateEqual(snapshotService, solutionObject2, solutionObject3); + validator.SolutionStateEqual(solutionObject2, solutionObject3); snapshot2.Dispose(); } @@ -331,6 +390,8 @@ public async Task OptionSet_Serialization_CustomValue() .WithChangedOption(CSharpCodeStyleOptions.VarWhenTypeIsApparent, newVarWhenTypeIsApparentValue) .WithChangedOption(CodeStyleOptions2.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, LanguageNames.VisualBasic, newPreferIntrinsicPredefinedTypeKeywordInMemberAccessValue))); + var validator = new SerializationValidator(workspace.Services); + await VerifyOptionSetsAsync(workspace, VerifyOptions).ConfigureAwait(false); void VerifyOptions(OptionSet options) @@ -463,7 +524,8 @@ public async Task SnapshotWithIdenticalAnalyzerFiles() var hostServices = MefHostServices.Create( MefHostServices.DefaultAssemblies.Add(typeof(Host.TemporaryStorageServiceFactory.TemporaryStorageService).Assembly)); - var project = new AdhocWorkspace(hostServices).CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); + using var workspace = new AdhocWorkspace(hostServices); + var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); using var temp = new TempRoot(); var dir = temp.CreateDirectory(); @@ -477,10 +539,10 @@ public async Task SnapshotWithIdenticalAnalyzerFiles() project = project.AddAnalyzerReferences(new[] { analyzer1, analyzer2 }); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(project.Solution.Workspace.Services); - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); + var validator = new SerializationValidator(workspace.Services); + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); - var recovered = await GetSolutionAsync(snapshotService, snapshot).ConfigureAwait(false); + var recovered = await validator.GetSolutionAsync(snapshot).ConfigureAwait(false); AssertEx.Equal(new[] { file1.Path, file2.Path }, recovered.GetProject(project.Id).AnalyzerReferences.Select(r => r.FullPath)); } @@ -490,7 +552,8 @@ public async Task SnapshotWithMissingReferencesTest() var hostServices = MefHostServices.Create( MefHostServices.DefaultAssemblies.Add(typeof(Host.TemporaryStorageServiceFactory.TemporaryStorageService).Assembly)); - var project = new AdhocWorkspace(hostServices).CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); + using var workspace = new AdhocWorkspace(hostServices); + var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); var metadata = new MissingMetadataReference(); var analyzer = new AnalyzerFileReference(Path.Combine(TempRoot.Root, "missing_reference"), new MissingAnalyzerLoader()); @@ -498,10 +561,11 @@ public async Task SnapshotWithMissingReferencesTest() project = project.AddMetadataReference(metadata); project = project.AddAnalyzerReference(analyzer); - var snapshotService = (new RemotableDataServiceFactory()).CreateService(project.Solution.Workspace.Services) as IRemotableDataService; - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); + var validator = new SerializationValidator(workspace.Services); + + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); // this shouldn't throw - var recovered = await GetSolutionAsync(snapshotService, snapshot).ConfigureAwait(false); + var recovered = await validator.GetSolutionAsync(snapshot).ConfigureAwait(false); } [Fact] @@ -509,12 +573,14 @@ public async Task UnknownLanguageTest() { var hostServices = MefHostServices.Create(MefHostServices.DefaultAssemblies.Add(typeof(NoCompilationConstants).Assembly)); - var project = new AdhocWorkspace(hostServices).CurrentSolution.AddProject("Project", "Project.dll", NoCompilationConstants.LanguageName); + using var workspace = new AdhocWorkspace(hostServices); + var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", NoCompilationConstants.LanguageName); + + var validator = new SerializationValidator(workspace.Services); - var snapshotService = (new RemotableDataServiceFactory()).CreateService(project.Solution.Workspace.Services) as IRemotableDataService; - using var snapshot = await snapshotService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); + using var snapshot = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(project.Solution, CancellationToken.None).ConfigureAwait(false); // this shouldn't throw - var recovered = await GetSolutionAsync(snapshotService, snapshot).ConfigureAwait(false); + var recovered = await validator.GetSolutionAsync(snapshot).ConfigureAwait(false); } [Fact] @@ -653,15 +719,17 @@ private static async Task GetXmlDocumentAsync(HostServices services) "); // currently portable layer doesn't support xml documment - var solution = new AdhocWorkspace(services).CurrentSolution - .AddProject("Project", "Project.dll", LanguageNames.CSharp) - .AddMetadataReference(MetadataReference.CreateFromFile(tempCorlib.Path)) - .Solution; + using var workspace = new AdhocWorkspace(services); + var solution = workspace.CurrentSolution + .AddProject("Project", "Project.dll", LanguageNames.CSharp) + .AddMetadataReference(MetadataReference.CreateFromFile(tempCorlib.Path)) + .Solution; + + var validator = new SerializationValidator(workspace.Services); - var snapshotService = (IRemotableDataService)new RemotableDataServiceFactory().CreateService(solution.Workspace.Services); - using var scope = await snapshotService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None); + using var scope = await validator.RemotableDataService.CreatePinnedRemotableDataScopeAsync(solution, CancellationToken.None); // recover solution from given snapshot - var recovered = await GetSolutionAsync(snapshotService, scope); + var recovered = await validator.GetSolutionAsync(scope); var compilation = await recovered.Projects.First().GetCompilationAsync(CancellationToken.None); var objectType = compilation.GetTypeByMetadataName("System.Object"); @@ -679,15 +747,16 @@ private static async Task VerifyOptionSetsAsync(Workspace workspace, Action(checksum).ConfigureAwait(false); + var solutionObject = await validator.GetValueAsync(checksum).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes); - await VerifyChecksumInServiceAsync(snapshotService, solutionObject.Options, WellKnownSynchronizationKind.OptionSet); + await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes); + await validator.VerifyChecksumInServiceAsync(solutionObject.Options, WellKnownSynchronizationKind.OptionSet); - var recoveredSolution = await GetSolutionAsync(snapshotService, snapshot); + var recoveredSolution = await validator.GetSolutionAsync(snapshot); // option should be exactly same Assert.Equal(0, recoveredSolution.Options.GetChangedOptions(workspace.Options).Count()); @@ -696,14 +765,6 @@ private static async Task VerifyOptionSetsAsync(Workspace workspace, Action GetSolutionAsync(IRemotableDataService service, PinnedRemotableDataScope syncScope) - { - var (solutionInfo, _) = await new TestAssetProvider(service).CreateSolutionInfoAndOptionsAsync(syncScope.SolutionChecksum, CancellationToken.None).ConfigureAwait(false); - - var workspace = new AdhocWorkspace(); - return workspace.AddSolution(solutionInfo); - } - private static async Task CloneAssetAsync(ISerializerService serializer, RemotableData asset) { using var stream = SerializableBytes.CreateWritableStream(); diff --git a/src/Workspaces/CoreTestUtilities/Extensions.cs b/src/Workspaces/CoreTestUtilities/Extensions.cs index 6b2833f839fd1..389aff84f86bb 100644 --- a/src/Workspaces/CoreTestUtilities/Extensions.cs +++ b/src/Workspaces/CoreTestUtilities/Extensions.cs @@ -17,40 +17,6 @@ namespace Microsoft.CodeAnalysis.UnitTests.Execution { - internal static class Extensions - { - public static async Task GetValueAsync(this IRemotableDataService service, Checksum checksum) - { - var syncService = (RemotableDataServiceFactory.Service)service; - var syncObject = (await syncService.TestOnly_GetRemotableDataAsync(checksum, CancellationToken.None).ConfigureAwait(false))!; - - using var stream = SerializableBytes.CreateWritableStream(); - using (var writer = new ObjectWriter(stream, leaveOpen: true)) - { - await syncObject.WriteObjectToAsync(writer, CancellationToken.None).ConfigureAwait(false); - } - - stream.Position = 0; - using var reader = ObjectReader.TryGetReader(stream); - - // deserialize bits to object - var serializer = syncService.Serializer_TestOnly; - return serializer.Deserialize(syncObject.Kind, reader, CancellationToken.None); - } - - public static ChecksumObjectCollection ToProjectObjects(this ProjectChecksumCollection collection, IRemotableDataService service) - => new ChecksumObjectCollection(service, collection); - - public static ChecksumObjectCollection ToDocumentObjects(this DocumentChecksumCollection collection, IRemotableDataService service) - => new ChecksumObjectCollection(service, collection); - - public static ChecksumObjectCollection ToDocumentObjects(this TextDocumentChecksumCollection collection, IRemotableDataService service) - => new ChecksumObjectCollection(service, collection); - - public static ChecksumObjectCollection ToDocumentObjects(this AnalyzerConfigDocumentChecksumCollection collection, IRemotableDataService service) - => new ChecksumObjectCollection(service, collection); - } - /// /// this is a helper collection for unit test. just packaging checksum collection with actual items. /// @@ -58,11 +24,12 @@ internal class ChecksumObjectCollection : RemotableData, IEnumerable where { public ImmutableArray Children { get; } - public ChecksumObjectCollection(IRemotableDataService service, ChecksumCollection collection) : base(collection.Checksum, collection.GetWellKnownSynchronizationKind()) + public ChecksumObjectCollection(SerializationValidator validator, ChecksumCollection collection) + : base(collection.Checksum, collection.GetWellKnownSynchronizationKind()) { // using .Result here since we don't want to convert all calls to this to async. // and none of ChecksumWithChildren actually use async - Children = ImmutableArray.CreateRange(collection.Select(c => service.GetValueAsync(c).Result)); + Children = ImmutableArray.CreateRange(collection.Select(c => validator.GetValueAsync(c).Result)); } public int Count => Children.Length; @@ -77,15 +44,4 @@ public ChecksumObjectCollection(IRemotableDataService service, ChecksumCollectio public override Task WriteObjectToAsync(ObjectWriter writer, CancellationToken cancellationToken) => throw new NotImplementedException("should not be called"); } - - internal sealed class TestAssetProvider : AbstractAssetProvider - { - private readonly IRemotableDataService _service; - - public TestAssetProvider(IRemotableDataService service) - => _service = service; - - public override Task GetAssetAsync(Checksum checksum, CancellationToken cancellationToken) - => _service.GetValueAsync(checksum); - } } diff --git a/src/Workspaces/CoreTestUtilities/SerializationValidator.cs b/src/Workspaces/CoreTestUtilities/SerializationValidator.cs new file mode 100644 index 0000000000000..d7bd454b7d167 --- /dev/null +++ b/src/Workspaces/CoreTestUtilities/SerializationValidator.cs @@ -0,0 +1,316 @@ +// 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 enable + +using System; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Execution; +using Microsoft.CodeAnalysis.Host; +using Microsoft.CodeAnalysis.Serialization; +using Microsoft.CodeAnalysis.Text; +using Microsoft.CodeAnalysis.UnitTests.Execution; +using Roslyn.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.UnitTests +{ + internal sealed class SerializationValidator + { + private sealed class AssetProvider : AbstractAssetProvider + { + private readonly SerializationValidator _validator; + + public AssetProvider(SerializationValidator validator) + => _validator = validator; + + public override Task GetAssetAsync(Checksum checksum, CancellationToken cancellationToken) + => _validator.GetValueAsync(checksum); + } + + public RemotableDataService RemotableDataService { get; } + public ISerializerService Serializer { get; } + + public SerializationValidator(HostWorkspaceServices services) + { + RemotableDataService = (RemotableDataService)services.GetRequiredService(); + Serializer = services.GetRequiredService(); + } + + public async Task GetValueAsync(Checksum checksum) + { + var data = (await RemotableDataService.TestOnly_GetRemotableDataAsync(checksum, CancellationToken.None).ConfigureAwait(false))!; + + using var stream = SerializableBytes.CreateWritableStream(); + using (var writer = new ObjectWriter(stream, leaveOpen: true)) + { + await data.WriteObjectToAsync(writer, CancellationToken.None).ConfigureAwait(false); + } + + stream.Position = 0; + using var reader = ObjectReader.TryGetReader(stream); + + // deserialize bits to object + return Serializer.Deserialize(data.Kind, reader, CancellationToken.None); + } + + public async Task GetSolutionAsync(PinnedRemotableDataScope scope) + { + var (solutionInfo, _) = await new AssetProvider(this).CreateSolutionInfoAndOptionsAsync(scope.SolutionChecksum, CancellationToken.None).ConfigureAwait(false); + + var workspace = new AdhocWorkspace(); + return workspace.AddSolution(solutionInfo); + } + + public ChecksumObjectCollection ToProjectObjects(ProjectChecksumCollection collection) + => new ChecksumObjectCollection(this, collection); + + public ChecksumObjectCollection ToDocumentObjects(DocumentChecksumCollection collection) + => new ChecksumObjectCollection(this, collection); + + public ChecksumObjectCollection ToDocumentObjects(TextDocumentChecksumCollection collection) + => new ChecksumObjectCollection(this, collection); + + public ChecksumObjectCollection ToDocumentObjects(AnalyzerConfigDocumentChecksumCollection collection) + => new ChecksumObjectCollection(this, collection); + + internal async Task VerifyAssetAsync(SolutionStateChecksums solutionObject) + { + await VerifyAssetSerializationAsync( + solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes, + (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)).ConfigureAwait(false); + + foreach (var projectChecksum in solutionObject.Projects) + { + var projectObject = await GetValueAsync(projectChecksum).ConfigureAwait(false); + await VerifyAssetAsync(projectObject).ConfigureAwait(false); + } + } + + internal async Task VerifyAssetAsync(ProjectStateChecksums projectObject) + { + var info = await VerifyAssetSerializationAsync( + projectObject.Info, WellKnownSynchronizationKind.ProjectAttributes, + (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)).ConfigureAwait(false); + + await VerifyAssetSerializationAsync( + projectObject.CompilationOptions, WellKnownSynchronizationKind.CompilationOptions, + (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); + + await VerifyAssetSerializationAsync( + projectObject.ParseOptions, WellKnownSynchronizationKind.ParseOptions, + (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); + + foreach (var checksum in projectObject.Documents) + { + var documentObject = await GetValueAsync(checksum).ConfigureAwait(false); + await VerifyAssetAsync(documentObject).ConfigureAwait(false); + } + + foreach (var checksum in projectObject.ProjectReferences) + { + await VerifyAssetSerializationAsync( + checksum, WellKnownSynchronizationKind.ProjectReference, + (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); + } + + foreach (var checksum in projectObject.MetadataReferences) + { + await VerifyAssetSerializationAsync( + checksum, WellKnownSynchronizationKind.MetadataReference, + (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); + } + + foreach (var checksum in projectObject.AnalyzerReferences) + { + await VerifyAssetSerializationAsync( + checksum, WellKnownSynchronizationKind.AnalyzerReference, + (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); + } + + foreach (var checksum in projectObject.AdditionalDocuments) + { + var documentObject = await GetValueAsync(checksum).ConfigureAwait(false); + await VerifyAssetAsync(documentObject).ConfigureAwait(false); + } + + foreach (var checksum in projectObject.AnalyzerConfigDocuments) + { + var documentObject = await GetValueAsync(checksum).ConfigureAwait(false); + await VerifyAssetAsync(documentObject).ConfigureAwait(false); + } + } + + internal async Task VerifyAssetAsync(DocumentStateChecksums documentObject) + { + var info = await VerifyAssetSerializationAsync( + documentObject.Info, WellKnownSynchronizationKind.DocumentAttributes, + (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)).ConfigureAwait(false); + + await VerifyAssetSerializationAsync( + documentObject.Text, WellKnownSynchronizationKind.SourceText, + (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); + } + + internal async Task VerifyAssetSerializationAsync( + Checksum checksum, + WellKnownSynchronizationKind kind, + Func assetGetter) + { + // re-create asset from object + var syncObject = (await RemotableDataService.TestOnly_GetRemotableDataAsync(checksum, CancellationToken.None).ConfigureAwait(false))!; + + var recoveredValue = await GetValueAsync(checksum).ConfigureAwait(false); + var recreatedSyncObject = assetGetter(recoveredValue, kind, Serializer); + + // make sure original object and re-created object are same. + SynchronizationObjectEqual(syncObject, recreatedSyncObject); + + return recoveredValue; + } + + internal async Task VerifySolutionStateSerializationAsync(Solution solution, Checksum solutionChecksum) + { + var solutionObjectFromSyncObject = await GetValueAsync(solutionChecksum); + Assert.True(solution.State.TryGetStateChecksums(out var solutionObjectFromSolution)); + + SolutionStateEqual(solutionObjectFromSolution, solutionObjectFromSyncObject); + } + + internal void SolutionStateEqual(SolutionStateChecksums solutionObject1, SolutionStateChecksums solutionObject2) + { + ChecksumWithChildrenEqual(solutionObject1, solutionObject2); + + ProjectStatesEqual(ToProjectObjects(solutionObject1.Projects), ToProjectObjects(solutionObject2.Projects)); + } + + internal void ProjectStateEqual(ProjectStateChecksums projectObjects1, ProjectStateChecksums projectObjects2) + { + ChecksumWithChildrenEqual(projectObjects1, projectObjects2); + + ChecksumWithChildrenEqual(ToDocumentObjects(projectObjects1.Documents), ToDocumentObjects(projectObjects2.Documents)); + ChecksumWithChildrenEqual(ToDocumentObjects(projectObjects1.AdditionalDocuments), ToDocumentObjects(projectObjects2.AdditionalDocuments)); + ChecksumWithChildrenEqual(ToDocumentObjects(projectObjects1.AnalyzerConfigDocuments), ToDocumentObjects(projectObjects2.AnalyzerConfigDocuments)); + } + + internal void ProjectStatesEqual(ChecksumObjectCollection projectObjects1, ChecksumObjectCollection projectObjects2) + { + SynchronizationObjectEqual(projectObjects1, projectObjects2); + + Assert.Equal(projectObjects1.Count, projectObjects2.Count); + + for (var i = 0; i < projectObjects1.Count; i++) + { + ProjectStateEqual(projectObjects1[i], projectObjects2[i]); + } + } + + internal static void ChecksumWithChildrenEqual(ChecksumObjectCollection checksums1, ChecksumObjectCollection checksums2) where T : ChecksumWithChildren + { + SynchronizationObjectEqual(checksums1, checksums2); + + Assert.Equal(checksums1.Count, checksums2.Count); + + for (var i = 0; i < checksums1.Count; i++) + { + ChecksumWithChildrenEqual(checksums1[i], checksums2[i]); + } + } + + internal static void ChecksumWithChildrenEqual(ChecksumWithChildren checksums1, ChecksumWithChildren checksums2) + { + Assert.Equal(checksums1.Checksum, checksums2.Checksum); + Assert.Equal(checksums1.Children.Count, checksums2.Children.Count); + + for (var i = 0; i < checksums1.Children.Count; i++) + { + var child1 = checksums1.Children[i]; + var child2 = checksums2.Children[i]; + + Assert.Equal(child1.GetType(), child2.GetType()); + + if (child1 is Checksum) + { + Assert.Equal((Checksum)child1, (Checksum)child2); + continue; + } + + ChecksumWithChildrenEqual((ChecksumCollection)child1, (ChecksumCollection)child2); + } + } + + internal async Task VerifySnapshotInServiceAsync( + ProjectStateChecksums projectObject, + int expectedDocumentCount, + int expectedProjectReferenceCount, + int expectedMetadataReferenceCount, + int expectedAnalyzerReferenceCount, + int expectedAdditionalDocumentCount) + { + await VerifyChecksumInServiceAsync(projectObject.Checksum, projectObject.GetWellKnownSynchronizationKind()).ConfigureAwait(false); + await VerifyChecksumInServiceAsync(projectObject.Info, WellKnownSynchronizationKind.ProjectAttributes).ConfigureAwait(false); + await VerifyChecksumInServiceAsync(projectObject.CompilationOptions, WellKnownSynchronizationKind.CompilationOptions).ConfigureAwait(false); + await VerifyChecksumInServiceAsync(projectObject.ParseOptions, WellKnownSynchronizationKind.ParseOptions).ConfigureAwait(false); + + await VerifyCollectionInService(ToDocumentObjects(projectObject.Documents), expectedDocumentCount).ConfigureAwait(false); + + await VerifyCollectionInService(projectObject.ProjectReferences, expectedProjectReferenceCount, WellKnownSynchronizationKind.ProjectReference).ConfigureAwait(false); + await VerifyCollectionInService(projectObject.MetadataReferences, expectedMetadataReferenceCount, WellKnownSynchronizationKind.MetadataReference).ConfigureAwait(false); + await VerifyCollectionInService(projectObject.AnalyzerReferences, expectedAnalyzerReferenceCount, WellKnownSynchronizationKind.AnalyzerReference).ConfigureAwait(false); + + await VerifyCollectionInService(ToDocumentObjects(projectObject.AdditionalDocuments), expectedAdditionalDocumentCount).ConfigureAwait(false); + } + + internal async Task VerifyCollectionInService(ChecksumCollection checksums, int expectedCount, WellKnownSynchronizationKind expectedItemKind) + { + await VerifyChecksumInServiceAsync(checksums.Checksum, checksums.GetWellKnownSynchronizationKind()).ConfigureAwait(false); + Assert.Equal(checksums.Count, expectedCount); + + foreach (var checksum in checksums) + { + await VerifyChecksumInServiceAsync(checksum, expectedItemKind).ConfigureAwait(false); + } + } + + internal async Task VerifyCollectionInService(ChecksumObjectCollection documents, int expectedCount) + { + await VerifySynchronizationObjectInServiceAsync(documents).ConfigureAwait(false); + Assert.Equal(documents.Count, expectedCount); + + foreach (var documentId in documents) + { + await VerifySnapshotInServiceAsync(documentId).ConfigureAwait(false); + } + } + + internal async Task VerifySnapshotInServiceAsync(DocumentStateChecksums documentObject) + { + await VerifyChecksumInServiceAsync(documentObject.Checksum, documentObject.GetWellKnownSynchronizationKind()).ConfigureAwait(false); + await VerifyChecksumInServiceAsync(documentObject.Info, WellKnownSynchronizationKind.DocumentAttributes).ConfigureAwait(false); + await VerifyChecksumInServiceAsync(documentObject.Text, WellKnownSynchronizationKind.SourceText).ConfigureAwait(false); + } + + internal async Task VerifySynchronizationObjectInServiceAsync(RemotableData syncObject) + => await VerifyChecksumInServiceAsync(syncObject.Checksum, syncObject.Kind).ConfigureAwait(false); + + internal async Task VerifyChecksumInServiceAsync(Checksum checksum, WellKnownSynchronizationKind kind) + { + Assert.NotNull(checksum); + var otherObject = (await RemotableDataService.TestOnly_GetRemotableDataAsync(checksum, CancellationToken.None).ConfigureAwait(false))!; + + ChecksumEqual(checksum, kind, otherObject.Checksum, otherObject.Kind); + } + + internal static void SynchronizationObjectEqual(T checksumObject1, T checksumObject2) where T : RemotableData + => ChecksumEqual(checksumObject1.Checksum, checksumObject1.Kind, checksumObject2.Checksum, checksumObject2.Kind); + + internal static void ChecksumEqual(Checksum checksum1, WellKnownSynchronizationKind kind1, Checksum checksum2, WellKnownSynchronizationKind kind2) + { + Assert.Equal(checksum1, checksum2); + Assert.Equal(kind1, kind2); + } + } +} diff --git a/src/Workspaces/CoreTestUtilities/SnapshotSerializationTestBase.cs b/src/Workspaces/CoreTestUtilities/SnapshotSerializationTestBase.cs deleted file mode 100644 index d88d198004cfd..0000000000000 --- a/src/Workspaces/CoreTestUtilities/SnapshotSerializationTestBase.cs +++ /dev/null @@ -1,310 +0,0 @@ -// 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 enable - -using System; -using System.Collections.Immutable; -using System.IO; -using System.Reflection; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Execution; -using Microsoft.CodeAnalysis.Host; -using Microsoft.CodeAnalysis.Options; -using Microsoft.CodeAnalysis.Serialization; -using Microsoft.CodeAnalysis.Shared.Extensions; -using Microsoft.CodeAnalysis.Test.Utilities; -using Microsoft.CodeAnalysis.Text; -using Microsoft.CodeAnalysis.UnitTests.Execution; -using Xunit; - -namespace Microsoft.CodeAnalysis.UnitTests -{ - [UseExportProvider] - public class SnapshotSerializationTestBase - { - internal static Solution CreateFullSolution(HostServices? hostServices = null) - { - var solution = new AdhocWorkspace(hostServices ?? Host.Mef.MefHostServices.DefaultHost).CurrentSolution; - var languages = ImmutableHashSet.Create(LanguageNames.CSharp, LanguageNames.VisualBasic); - var solutionOptions = solution.Workspace.Services.GetRequiredService().GetSerializableOptionsSnapshot(languages); - solution = solution.WithOptions(solutionOptions); - - var csCode = "class A { }"; - var project1 = solution.AddProject("Project", "Project.dll", LanguageNames.CSharp); - var document1 = project1.AddDocument("Document1", SourceText.From(csCode)); - - var vbCode = "Class B\r\nEnd Class"; - var project2 = document1.Project.Solution.AddProject("Project2", "Project2.dll", LanguageNames.VisualBasic); - var document2 = project2.AddDocument("Document2", SourceText.From(vbCode)); - - solution = document2.Project.Solution.GetRequiredProject(project1.Id) - .AddProjectReference(new ProjectReference(project2.Id, ImmutableArray.Create("test"))) - .AddMetadataReference(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)) - .AddAnalyzerReference(new AnalyzerFileReference(Path.Combine(TempRoot.Root, "path1"), new TestAnalyzerAssemblyLoader())) - .AddAdditionalDocument("Additional", SourceText.From("hello"), ImmutableArray.Create("test"), @".\Add").Project.Solution; - - return solution - .WithAnalyzerReferences(new[] { new AnalyzerFileReference(Path.Combine(TempRoot.Root, "path2"), new TestAnalyzerAssemblyLoader()) }) - .AddAnalyzerConfigDocuments( - ImmutableArray.Create( - DocumentInfo.Create( - DocumentId.CreateNewId(project1.Id), - ".editorconfig", - loader: TextLoader.From(TextAndVersion.Create(SourceText.From("root = true"), VersionStamp.Create()))))); - } - - internal static async Task VerifyAssetAsync(IRemotableDataService service, SolutionStateChecksums solutionObject) - { - await VerifyAssetSerializationAsync( - service, solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes, - (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)).ConfigureAwait(false); - - foreach (var projectChecksum in solutionObject.Projects) - { - var projectObject = await service.GetValueAsync(projectChecksum).ConfigureAwait(false); - await VerifyAssetAsync(service, projectObject).ConfigureAwait(false); - } - } - - internal static async Task VerifyAssetAsync(IRemotableDataService service, ProjectStateChecksums projectObject) - { - var info = await VerifyAssetSerializationAsync( - service, projectObject.Info, WellKnownSynchronizationKind.ProjectAttributes, - (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)).ConfigureAwait(false); - - await VerifyAssetSerializationAsync( - service, projectObject.CompilationOptions, WellKnownSynchronizationKind.CompilationOptions, - (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); - - await VerifyAssetSerializationAsync( - service, projectObject.ParseOptions, WellKnownSynchronizationKind.ParseOptions, - (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); - - foreach (var checksum in projectObject.Documents) - { - var documentObject = await service.GetValueAsync(checksum).ConfigureAwait(false); - await VerifyAssetAsync(service, documentObject).ConfigureAwait(false); - } - - foreach (var checksum in projectObject.ProjectReferences) - { - await VerifyAssetSerializationAsync( - service, checksum, WellKnownSynchronizationKind.ProjectReference, - (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); - } - - foreach (var checksum in projectObject.MetadataReferences) - { - await VerifyAssetSerializationAsync( - service, checksum, WellKnownSynchronizationKind.MetadataReference, - (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); - } - - foreach (var checksum in projectObject.AnalyzerReferences) - { - await VerifyAssetSerializationAsync( - service, checksum, WellKnownSynchronizationKind.AnalyzerReference, - (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); - } - - foreach (var checksum in projectObject.AdditionalDocuments) - { - var documentObject = await service.GetValueAsync(checksum).ConfigureAwait(false); - await VerifyAssetAsync(service, documentObject).ConfigureAwait(false); - } - - foreach (var checksum in projectObject.AnalyzerConfigDocuments) - { - var documentObject = await service.GetValueAsync(checksum).ConfigureAwait(false); - await VerifyAssetAsync(service, documentObject).ConfigureAwait(false); - } - } - - internal static async Task VerifyAssetAsync(IRemotableDataService service, DocumentStateChecksums documentObject) - { - var info = await VerifyAssetSerializationAsync( - service, documentObject.Info, WellKnownSynchronizationKind.DocumentAttributes, - (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)).ConfigureAwait(false); - - await VerifyAssetSerializationAsync( - service, documentObject.Text, WellKnownSynchronizationKind.SourceText, - (v, k, s) => new SolutionAsset(s.CreateChecksum(v, CancellationToken.None), v, s)); - } - - internal static async Task VerifyAssetSerializationAsync( - IRemotableDataService service, - Checksum checksum, - WellKnownSynchronizationKind kind, - Func assetGetter) - { - // re-create asset from object - var syncService = (RemotableDataServiceFactory.Service)service; - var syncObject = (await syncService.TestOnly_GetRemotableDataAsync(checksum, CancellationToken.None).ConfigureAwait(false))!; - - var recoveredValue = await service.GetValueAsync(checksum).ConfigureAwait(false); - var recreatedSyncObject = assetGetter(recoveredValue, kind, syncService.Serializer_TestOnly); - - // make sure original object and re-created object are same. - SynchronizationObjectEqual(syncObject, recreatedSyncObject); - - return recoveredValue; - } - - internal static async Task VerifySolutionStateSerializationAsync(IRemotableDataService service, Solution solution, Checksum solutionChecksum) - { - var solutionObjectFromSyncObject = await service.GetValueAsync(solutionChecksum); - Assert.True(solution.State.TryGetStateChecksums(out var solutionObjectFromSolution)); - - SolutionStateEqual(service, solutionObjectFromSolution, solutionObjectFromSyncObject); - } - - internal static void SolutionStateEqual(IRemotableDataService service, SolutionStateChecksums solutionObject1, SolutionStateChecksums solutionObject2) - { - ChecksumWithChildrenEqual(solutionObject1, solutionObject2); - - ProjectStatesEqual(service, solutionObject1.Projects.ToProjectObjects(service), solutionObject2.Projects.ToProjectObjects(service)); - } - - internal static void ProjectStateEqual(IRemotableDataService service, ProjectStateChecksums projectObjects1, ProjectStateChecksums projectObjects2) - { - ChecksumWithChildrenEqual(projectObjects1, projectObjects2); - - ChecksumWithChildrenEqual(projectObjects1.Documents.ToDocumentObjects(service), projectObjects2.Documents.ToDocumentObjects(service)); - ChecksumWithChildrenEqual(projectObjects1.AdditionalDocuments.ToDocumentObjects(service), projectObjects2.AdditionalDocuments.ToDocumentObjects(service)); - ChecksumWithChildrenEqual(projectObjects1.AnalyzerConfigDocuments.ToDocumentObjects(service), projectObjects2.AnalyzerConfigDocuments.ToDocumentObjects(service)); - } - - internal static void ProjectStatesEqual(IRemotableDataService service, ChecksumObjectCollection projectObjects1, ChecksumObjectCollection projectObjects2) - { - SynchronizationObjectEqual(projectObjects1, projectObjects2); - - Assert.Equal(projectObjects1.Count, projectObjects2.Count); - - for (var i = 0; i < projectObjects1.Count; i++) - { - ProjectStateEqual(service, projectObjects1[i], projectObjects2[i]); - } - } - - internal static void ChecksumWithChildrenEqual(ChecksumObjectCollection checksums1, ChecksumObjectCollection checksums2) where T : ChecksumWithChildren - { - SynchronizationObjectEqual(checksums1, checksums2); - - Assert.Equal(checksums1.Count, checksums2.Count); - - for (var i = 0; i < checksums1.Count; i++) - { - ChecksumWithChildrenEqual(checksums1[i], checksums2[i]); - } - } - - internal static void ChecksumWithChildrenEqual(ChecksumWithChildren checksums1, ChecksumWithChildren checksums2) - { - Assert.Equal(checksums1.Checksum, checksums2.Checksum); - Assert.Equal(checksums1.Children.Count, checksums2.Children.Count); - - for (var i = 0; i < checksums1.Children.Count; i++) - { - var child1 = checksums1.Children[i]; - var child2 = checksums2.Children[i]; - - Assert.Equal(child1.GetType(), child2.GetType()); - - if (child1 is Checksum) - { - Assert.Equal((Checksum)child1, (Checksum)child2); - continue; - } - - ChecksumWithChildrenEqual((ChecksumCollection)child1, (ChecksumCollection)child2); - } - } - - internal static async Task VerifySnapshotInServiceAsync( - IRemotableDataService snapshotService, - ProjectStateChecksums projectObject, - int expectedDocumentCount, - int expectedProjectReferenceCount, - int expectedMetadataReferenceCount, - int expectedAnalyzerReferenceCount, - int expectedAdditionalDocumentCount) - { - await VerifyChecksumInServiceAsync(snapshotService, projectObject.Checksum, projectObject.GetWellKnownSynchronizationKind()).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, projectObject.Info, WellKnownSynchronizationKind.ProjectAttributes).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, projectObject.CompilationOptions, WellKnownSynchronizationKind.CompilationOptions).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, projectObject.ParseOptions, WellKnownSynchronizationKind.ParseOptions).ConfigureAwait(false); - - await VerifyCollectionInService(snapshotService, projectObject.Documents.ToDocumentObjects(snapshotService), expectedDocumentCount).ConfigureAwait(false); - - await VerifyCollectionInService(snapshotService, projectObject.ProjectReferences, expectedProjectReferenceCount, WellKnownSynchronizationKind.ProjectReference).ConfigureAwait(false); - await VerifyCollectionInService(snapshotService, projectObject.MetadataReferences, expectedMetadataReferenceCount, WellKnownSynchronizationKind.MetadataReference).ConfigureAwait(false); - await VerifyCollectionInService(snapshotService, projectObject.AnalyzerReferences, expectedAnalyzerReferenceCount, WellKnownSynchronizationKind.AnalyzerReference).ConfigureAwait(false); - - await VerifyCollectionInService(snapshotService, projectObject.AdditionalDocuments.ToDocumentObjects(snapshotService), expectedAdditionalDocumentCount).ConfigureAwait(false); - } - - internal static async Task VerifyCollectionInService(IRemotableDataService snapshotService, ChecksumCollection checksums, int expectedCount, WellKnownSynchronizationKind expectedItemKind) - { - await VerifyChecksumInServiceAsync(snapshotService, checksums.Checksum, checksums.GetWellKnownSynchronizationKind()).ConfigureAwait(false); - Assert.Equal(checksums.Count, expectedCount); - - foreach (var checksum in checksums) - { - await VerifyChecksumInServiceAsync(snapshotService, checksum, expectedItemKind).ConfigureAwait(false); - } - } - - internal static async Task VerifyCollectionInService(IRemotableDataService snapshotService, ChecksumObjectCollection documents, int expectedCount) - { - await VerifySynchronizationObjectInServiceAsync(snapshotService, documents).ConfigureAwait(false); - Assert.Equal(documents.Count, expectedCount); - - foreach (var documentId in documents) - { - await VerifySnapshotInServiceAsync(snapshotService, documentId).ConfigureAwait(false); - } - } - - internal static async Task VerifySnapshotInServiceAsync(IRemotableDataService snapshotService, DocumentStateChecksums documentObject) - { - await VerifyChecksumInServiceAsync(snapshotService, documentObject.Checksum, documentObject.GetWellKnownSynchronizationKind()).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, documentObject.Info, WellKnownSynchronizationKind.DocumentAttributes).ConfigureAwait(false); - await VerifyChecksumInServiceAsync(snapshotService, documentObject.Text, WellKnownSynchronizationKind.SourceText).ConfigureAwait(false); - } - - internal static async Task VerifySynchronizationObjectInServiceAsync(IRemotableDataService snapshotService, RemotableData syncObject) - => await VerifyChecksumInServiceAsync(snapshotService, syncObject.Checksum, syncObject.Kind).ConfigureAwait(false); - - internal static async Task VerifyChecksumInServiceAsync(IRemotableDataService snapshotService, Checksum checksum, WellKnownSynchronizationKind kind) - { - Assert.NotNull(checksum); - var service = (RemotableDataServiceFactory.Service)snapshotService; - var otherObject = (await service.TestOnly_GetRemotableDataAsync(checksum, CancellationToken.None).ConfigureAwait(false))!; - - ChecksumEqual(checksum, kind, otherObject.Checksum, otherObject.Kind); - } - - internal static void SynchronizationObjectEqual(T checksumObject1, T checksumObject2) where T : RemotableData - => ChecksumEqual(checksumObject1.Checksum, checksumObject1.Kind, checksumObject2.Checksum, checksumObject2.Kind); - - internal static void ChecksumEqual(Checksum checksum1, WellKnownSynchronizationKind kind1, Checksum checksum2, WellKnownSynchronizationKind kind2) - { - Assert.Equal(checksum1, checksum2); - Assert.Equal(kind1, kind2); - } - - private class TestAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader - { - public void AddDependencyLocation(string fullPath) - { - } - - public Assembly LoadFromPath(string fullPath) - => Assembly.LoadFrom(fullPath); - } - } -}