/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/VisualStudio/Core/Test.Next/Remote/SnapshotSerializationTests.cs
760 строк
35 KB
Cyrus Najmabadi
Use raw strings in tests
09 июл 2025, 08:52
09 июл 2025, 08:52
f265dce
Код
Авторство
О чём код?
// 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.Immutable; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.CodeAnalysis.Diagnostics; using Microsoft.CodeAnalysis.Remote.Testing; using Microsoft.CodeAnalysis.Serialization; using Microsoft.CodeAnalysis.Shared.Extensions; using Microsoft.CodeAnalysis.Test.Utilities; using Microsoft.CodeAnalysis.Text; using Microsoft.CodeAnalysis.UnitTests; using Roslyn.Test.Utilities; using Roslyn.Utilities; using Xunit; namespace Microsoft.CodeAnalysis.Remote.UnitTests; [CollectionDefinition(Name)] public sealed class AssemblyLoadTestFixtureCollection : ICollectionFixture<AssemblyLoadTestFixture> { public const string Name = nameof(AssemblyLoadTestFixtureCollection); private AssemblyLoadTestFixtureCollection() { } } [Collection(AssemblyLoadTestFixtureCollection.Name)] [UseExportProvider] public sealed class SnapshotSerializationTests(AssemblyLoadTestFixture testFixture) { private readonly AssemblyLoadTestFixture _testFixture = testFixture; private static Workspace CreateWorkspace(Type[] additionalParts = null) => new AdhocWorkspace(FeaturesTestCompositions.Features.AddParts(additionalParts).WithTestHostParts(TestHost.OutOfProcess).GetHostServices()); internal static Solution SetFullSolution(Workspace workspace) { workspace.SetCurrentSolution(solution => { 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, ["test"])) .AddMetadataReference(MetadataReference.CreateFromFile(typeof(object).Assembly.Location)) .AddAnalyzerReference(new AnalyzerFileReference(Path.Combine(TempRoot.Root, "path1"), new TestAnalyzerAssemblyLoader())) .AddAdditionalDocument("Additional", SourceText.From("hello"), ["test"], @".\Add").Project.Solution; return solution .WithAnalyzerReferences([new AnalyzerFileReference(Path.Combine(TempRoot.Root, "path2"), new TestAnalyzerAssemblyLoader())]) .AddAnalyzerConfigDocuments([DocumentInfo.Create( DocumentId.CreateNewId(project1.Id), ".editorconfig", loader: TextLoader.From(TextAndVersion.Create(SourceText.From("root = true"), VersionStamp.Create())))]); }, WorkspaceChangeKind.SolutionChanged); return workspace.CurrentSolution; } private static async Task<SolutionAsset> GetRequiredAssetAsync(SolutionAssetStorage.Scope scope, Checksum checksum) { var data = await scope.GetTestAccessor().GetAssetAsync(checksum, CancellationToken.None); Contract.ThrowIfNull(data); return new(checksum, data); } [Fact] public async Task CreateSolutionSnapshotId_Empty() { using var workspace = CreateWorkspace(); var solution = workspace.CurrentSolution; var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None); var checksum = scope.SolutionChecksum; var solutionSyncObject = await GetRequiredAssetAsync(scope, checksum); await validator.VerifySynchronizationObjectInServiceAsync(solutionSyncObject); var solutionCompilationObject = await validator.GetValueAsync<SolutionCompilationStateChecksums>(checksum); var solutionObject = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject.SolutionState); await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes); Assert.Equal(0, solutionObject.Projects.Length); } [Fact] public async Task CreateSolutionSnapshotId_Empty_Serialization() { using var workspace = CreateWorkspace(); var solution = workspace.CurrentSolution; var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None); await validator.VerifySolutionStateSerializationAsync(solution, scope.SolutionChecksum); } [Fact] public async Task CreateSolutionSnapshotId_Project() { using var workspace = CreateWorkspace(); var solution = workspace.CurrentSolution; var project = solution.AddProject("Project", "Project.dll", LanguageNames.CSharp); var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(project.Solution, CancellationToken.None); var checksum = scope.SolutionChecksum; var solutionSyncObject = await GetRequiredAssetAsync(scope, checksum); await validator.VerifySynchronizationObjectInServiceAsync(solutionSyncObject); var solutionCompilationObject = await validator.GetValueAsync<SolutionCompilationStateChecksums>(checksum); var solutionObject = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject.SolutionState); await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes); Assert.Equal(1, solutionObject.Projects.Length); } [Fact] public async Task CreateSolutionSnapshotId_Project_Serialization() { using var workspace = CreateWorkspace(); var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); var validator = new SerializationValidator(workspace.Services); using var snapshot = await validator.AssetStorage.StoreAssetsAsync(project.Solution, CancellationToken.None); await validator.VerifySolutionStateSerializationAsync(project.Solution, snapshot.SolutionChecksum); } [Fact] public async Task CreateSolutionSnapshotId() { var code = "class A { }"; using var workspace = CreateWorkspace(); var document = workspace.CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp).AddDocument("Document", SourceText.From(code)); var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(document.Project.Solution, CancellationToken.None); var syncObject = await GetRequiredAssetAsync(scope, scope.SolutionChecksum); var solutionCompilationObject = await validator.GetValueAsync<SolutionCompilationStateChecksums>(syncObject.Checksum); var solutionObject = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject.SolutionState); await validator.VerifySynchronizationObjectInServiceAsync(syncObject); await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes); } [Fact] public async Task CreateSolutionSnapshotId_Serialization() { var code = "class A { }"; using var workspace = CreateWorkspace(); var solution = workspace.CurrentSolution; var document = solution.AddProject("Project", "Project.dll", LanguageNames.CSharp).AddDocument("Document", SourceText.From(code)); var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(document.Project.Solution, CancellationToken.None); await validator.VerifySolutionStateSerializationAsync(document.Project.Solution, scope.SolutionChecksum); } [Fact] public async Task CreateSolutionSnapshotId_Full() { using var workspace = CreateWorkspace(); var solution = SetFullSolution(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 validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None); var syncObject = await GetRequiredAssetAsync(scope, scope.SolutionChecksum); var solutionCompilationObject = await validator.GetValueAsync<SolutionCompilationStateChecksums>(syncObject.Checksum); var solutionObject = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject.SolutionState); await validator.VerifySynchronizationObjectInServiceAsync(syncObject); await validator.VerifyChecksumInServiceAsync(solutionObject.Attributes, WellKnownSynchronizationKind.SolutionAttributes); Assert.Equal(2, solutionObject.Projects.Length); } [Fact] public async Task CreateSolutionSnapshotId_Full_Serialization() { using var workspace = CreateWorkspace(); var solution = SetFullSolution(workspace); var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None); await validator.VerifySolutionStateSerializationAsync(solution, scope.SolutionChecksum); } [Fact] public async Task CreateSolutionSnapshotId_Full_Asset_Serialization() { using var workspace = CreateWorkspace(); var solution = SetFullSolution(workspace); var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None); var solutionCompilationObject = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope.SolutionChecksum); var solutionObject = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject.SolutionState); await validator.VerifyAssetAsync(solutionObject); } [Fact] public async Task CreateSolutionSnapshotId_Full_Asset_Serialization_Desktop() { using var workspace = CreateWorkspace(); var solution = SetFullSolution(workspace); var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None); var solutionCompilationObject = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope.SolutionChecksum); var solutionObject = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject.SolutionState); await validator.VerifyAssetAsync(solutionObject); } [Fact] public async Task CreateSolutionSnapshotId_Duplicate() { using var workspace = CreateWorkspace(); var solution = SetFullSolution(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. SolutionCompilationStateChecksums solutionCompilationId1; SolutionCompilationStateChecksums solutionCompilationId2; SolutionStateChecksums solutionId1; SolutionStateChecksums solutionId2; var validator = new SerializationValidator(workspace.Services); using (var scope1 = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None).ConfigureAwait(false)) { solutionCompilationId1 = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope1.SolutionChecksum); solutionId1 = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationId1.SolutionState); } using (var scope2 = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None).ConfigureAwait(false)) { solutionCompilationId2 = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope2.SolutionChecksum); solutionId2 = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationId2.SolutionState); } validator.SolutionCompilationStateEqual(solutionCompilationId1, solutionCompilationId2); // 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<Exception>(() => validator.SolutionStateEqual(solutionId1, solutionId2)); } [Fact] public void MetadataReference_RoundTrip_Test() { using var workspace = CreateWorkspace(); var reference = MetadataReference.CreateFromFile(typeof(object).Assembly.Location); var serializer = workspace.Services.GetService<ISerializerService>(); var assetFromFile = new SolutionAsset(serializer.CreateChecksum(reference, CancellationToken.None), reference); var assetFromStorage = CloneAsset(serializer, assetFromFile); _ = CloneAsset(serializer, assetFromStorage); } [Fact] public async Task Workspace_RoundTrip_Test() { using var workspace = CreateWorkspace(); var solution = SetFullSolution(workspace); var validator = new SerializationValidator(workspace.Services); var scope1 = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None); // recover solution from given snapshot var recovered = await validator.GetSolutionAsync(scope1); var solutionCompilationObject1 = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope1.SolutionChecksum); var solutionObject1 = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject1.SolutionState); // create new snapshot from recovered solution using var scope2 = await validator.AssetStorage.StoreAssetsAsync(recovered, CancellationToken.None); // verify asset created by recovered solution is good var solutionCompilationObject2 = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope2.SolutionChecksum); var solutionObject2 = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject2.SolutionState); await validator.VerifyAssetAsync(solutionObject2); // verify snapshots created from original solution and recovered solution are same validator.SolutionStateEqual(solutionObject1, solutionObject2); // recover new solution from recovered solution var roundtrip = await validator.GetSolutionAsync(scope2); // create new snapshot from round tripped solution using var scope3 = await validator.AssetStorage.StoreAssetsAsync(roundtrip, CancellationToken.None); // verify asset created by round trip solution is good var solutionCompilationObject3 = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope3.SolutionChecksum); var solutionObject3 = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject3.SolutionState); await validator.VerifyAssetAsync(solutionObject3); // verify snapshots created from original solution and round trip solution are same. validator.SolutionStateEqual(solutionObject2, solutionObject3); } [Fact] public async Task Workspace_RoundTrip_Test_Desktop() { using var workspace = CreateWorkspace(); var solution = SetFullSolution(workspace); var validator = new SerializationValidator(workspace.Services); var scope1 = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None); // recover solution from given snapshot var recovered = await validator.GetSolutionAsync(scope1); var solutionCompilationObject1 = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope1.SolutionChecksum); var solutionObject1 = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject1.SolutionState); // create new snapshot from recovered solution using var scope2 = await validator.AssetStorage.StoreAssetsAsync(recovered, CancellationToken.None); // verify asset created by recovered solution is good var solutionCompilationObject2 = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope2.SolutionChecksum); var solutionObject2 = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject2.SolutionState); await validator.VerifyAssetAsync(solutionObject2); // verify snapshots created from original solution and recovered solution are same validator.SolutionStateEqual(solutionObject1, solutionObject2); scope1.Dispose(); // recover new solution from recovered solution var roundtrip = await validator.GetSolutionAsync(scope2); // create new snapshot from round tripped solution using var scope3 = await validator.AssetStorage.StoreAssetsAsync(roundtrip, CancellationToken.None); // verify asset created by round trip solution is good var solutionCompilationObject3 = await validator.GetValueAsync<SolutionCompilationStateChecksums>(scope3.SolutionChecksum); var solutionObject3 = await validator.GetValueAsync<SolutionStateChecksums>(solutionCompilationObject3.SolutionState); await validator.VerifyAssetAsync(solutionObject3); // verify snapshots created from original solution and round trip solution are same. validator.SolutionStateEqual(solutionObject2, solutionObject3); } [Fact] public void Missing_Metadata_Serialization_Test() { using var workspace = CreateWorkspace(); var serializer = workspace.Services.GetService<ISerializerService>(); var reference = new MissingMetadataReference(); // make sure this doesn't throw var assetFromFile = new SolutionAsset(serializer.CreateChecksum(reference, CancellationToken.None), reference); var assetFromStorage = CloneAsset(serializer, assetFromFile); _ = CloneAsset(serializer, assetFromStorage); } [Fact] public void Missing_Analyzer_Serialization_Test() { using var workspace = CreateWorkspace(); var serializer = workspace.Services.GetService<ISerializerService>(); var reference = new AnalyzerFileReference(Path.Combine(TempRoot.Root, "missing_reference"), new MissingAnalyzerLoader()); // make sure this doesn't throw var assetFromFile = new SolutionAsset(serializer.CreateChecksum(reference, CancellationToken.None), reference); var assetFromStorage = CloneAsset(serializer, assetFromFile); _ = CloneAsset(serializer, assetFromStorage); } [Fact] public void Missing_Analyzer_Serialization_Desktop_Test() { using var workspace = CreateWorkspace(); var serializer = workspace.Services.GetService<ISerializerService>(); var reference = new AnalyzerFileReference(Path.Combine(TempRoot.Root, "missing_reference"), new MissingAnalyzerLoader()); // make sure this doesn't throw var assetFromFile = new SolutionAsset(serializer.CreateChecksum(reference, CancellationToken.None), reference); var assetFromStorage = CloneAsset(serializer, assetFromFile); _ = CloneAsset(serializer, assetFromStorage); } [Fact] public void RoundTrip_Analyzer_Serialization_Test() { using var tempRoot = new TempRoot(); using var workspace = CreateWorkspace(); var serializer = workspace.Services.GetService<ISerializerService>(); // actually shadow copy content var location = typeof(object).Assembly.Location; var file = tempRoot.CreateFile("shadow", "dll"); file.CopyContentFrom(location); var reference = new AnalyzerFileReference(location, new MockShadowCopyAnalyzerAssemblyLoader(ImmutableDictionary<string, string>.Empty.Add(location, file.Path))); // make sure this doesn't throw var assetFromFile = new SolutionAsset(serializer.CreateChecksum(reference, CancellationToken.None), reference); var assetFromStorage = CloneAsset(serializer, assetFromFile); _ = CloneAsset(serializer, assetFromStorage); } [Fact] public void RoundTrip_Analyzer_Serialization_Desktop_Test() { using var tempRoot = new TempRoot(); using var workspace = CreateWorkspace(); var serializer = workspace.Services.GetService<ISerializerService>(); // actually shadow copy content var location = typeof(object).Assembly.Location; var file = tempRoot.CreateFile("shadow", "dll"); file.CopyContentFrom(location); var reference = new AnalyzerFileReference(location, new MockShadowCopyAnalyzerAssemblyLoader(ImmutableDictionary<string, string>.Empty.Add(location, file.Path))); // make sure this doesn't throw var assetFromFile = new SolutionAsset(serializer.CreateChecksum(reference, CancellationToken.None), reference); var assetFromStorage = CloneAsset(serializer, assetFromFile); _ = CloneAsset(serializer, assetFromStorage); } [Fact] public void ShadowCopied_Analyzer_Serialization_Desktop_Test() { using var tempRoot = new TempRoot(); using var workspace = CreateWorkspace(); var reference = CreateShadowCopiedAnalyzerReference(tempRoot); var serializer = workspace.Services.GetService<ISerializerService>(); // make sure this doesn't throw var assetFromFile = new SolutionAsset(serializer.CreateChecksum(reference, CancellationToken.None), reference); // this will verify serialized analyzer reference return same checksum as the original one _ = CloneAsset(serializer, assetFromFile); } [Fact, WorkItem("https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1107294")] public async Task SnapshotWithIdenticalAnalyzerFiles() { using var workspace = CreateWorkspace(); var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", LanguageNames.CSharp); using var temp = new TempRoot(); var dir = temp.CreateDirectory(); // create two analyzer assembly files whose content is identical but path is different: var file1 = dir.CreateFile("analyzer1.dll").CopyContentFrom(_testFixture.FaultyAnalyzer); var file2 = dir.CreateFile("analyzer2.dll").CopyContentFrom(_testFixture.FaultyAnalyzer); var analyzer1 = new AnalyzerFileReference(file1.Path, TestAnalyzerAssemblyLoader.LoadNotImplemented); var analyzer2 = new AnalyzerFileReference(file2.Path, TestAnalyzerAssemblyLoader.LoadNotImplemented); project = project.AddAnalyzerReferences([analyzer1, analyzer2]); var validator = new SerializationValidator(workspace.Services); using var snapshot = await validator.AssetStorage.StoreAssetsAsync(project.Solution, CancellationToken.None); var recovered = await validator.GetSolutionAsync(snapshot); AssertEx.Equal([file1.Path, file2.Path], recovered.GetProject(project.Id).AnalyzerReferences.Select(r => r.FullPath)); } [Fact] public async Task SnapshotWithMissingReferencesTest() { using var workspace = CreateWorkspace(); 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()); project = project.AddMetadataReference(metadata); project = project.AddAnalyzerReference(analyzer); var validator = new SerializationValidator(workspace.Services); using var snapshot = await validator.AssetStorage.StoreAssetsAsync(project.Solution, CancellationToken.None); // this shouldn't throw var recovered = await validator.GetSolutionAsync(snapshot); } [Fact] public async Task UnknownLanguageTest() { using var workspace = CreateWorkspace([typeof(NoCompilationLanguageService)]); var project = workspace.CurrentSolution.AddProject("Project", "Project.dll", NoCompilationConstants.LanguageName); var validator = new SerializationValidator(workspace.Services); using var snapshot = await validator.AssetStorage.StoreAssetsAsync(project.Solution, CancellationToken.None); // this shouldn't throw var recovered = await validator.GetSolutionAsync(snapshot); } [Fact] public async Task EmptyAssetChecksumTest() { var document = CreateWorkspace().CurrentSolution.AddProject("empty", "empty", LanguageNames.CSharp).AddDocument("empty", SourceText.From("")); var serializer = document.Project.Solution.Services.GetService<ISerializerService>(); var text = await document.GetTextAsync().ConfigureAwait(false); var source = new SerializableSourceText(text, text.GetContentHash()).ContentChecksum; var metadata = serializer.CreateChecksum(new MissingMetadataReference(), CancellationToken.None); var analyzer = serializer.CreateChecksum(new AnalyzerFileReference(Path.Combine(TempRoot.Root, "missing"), new MissingAnalyzerLoader()), CancellationToken.None); Assert.NotEqual(source, metadata); Assert.NotEqual(source, analyzer); Assert.NotEqual(metadata, analyzer); } [Fact] public async Task VBParseOptionsInCompilationOptions() { var project = CreateWorkspace().CurrentSolution.AddProject("empty", "empty", LanguageNames.VisualBasic); project = project.WithCompilationOptions( ((VisualBasic.VisualBasicCompilationOptions)project.CompilationOptions).WithParseOptions((VisualBasic.VisualBasicParseOptions)project.ParseOptions)); var checksum = await project.State.GetChecksumAsync(CancellationToken.None); Assert.True(checksum != Checksum.Null); } [Fact] public async Task TestMetadataXmlDocComment() { using var tempRoot = new TempRoot(); // get original assembly location var mscorlibLocation = typeof(object).Assembly.Location; // set up dll and xml doc content var tempDir = tempRoot.CreateDirectory(); var tempCorlib = tempDir.CopyFile(mscorlibLocation); var tempCorlibXml = tempDir.CreateFile(Path.ChangeExtension(tempCorlib.Path, "xml")); tempCorlibXml.WriteAllText(""" <?xml version="1.0" encoding="utf-8"?> <doc> <assembly> <name>mscorlib</name> </assembly> <members> <member name="T:System.Object"> <summary>Supports all classes in the .NET Framework class hierarchy and provides low-level services to derived classes. This is the ultimate base class of all classes in the .NET Framework; it is the root of the type hierarchy.To browse the .NET Framework source code for this type, see the Reference Source.</summary> </member> </members> </doc> """); using var workspace = CreateWorkspace(); var solution = workspace.CurrentSolution .AddProject("Project", "Project.dll", LanguageNames.CSharp) .AddMetadataReference(MetadataReference.CreateFromFile(tempCorlib.Path)) .Solution; var validator = new SerializationValidator(workspace.Services); using var scope = await validator.AssetStorage.StoreAssetsAsync(solution, CancellationToken.None); // recover solution from given snapshot var recovered = await validator.GetSolutionAsync(scope); var compilation = await recovered.Projects.First().GetCompilationAsync(CancellationToken.None); var objectType = compilation.GetTypeByMetadataName("System.Object"); var xmlDocComment = objectType.GetDocumentationCommentXml(); Assert.False(string.IsNullOrEmpty(xmlDocComment)); } [Fact] public void TestEncodingSerialization() { using var workspace = CreateWorkspace(); var serializer = workspace.Services.GetService<ISerializerService>(); // test with right serializable encoding var sourceText = SourceText.From("Hello", Encoding.UTF8); var serializableSourceText = new SerializableSourceText(sourceText, sourceText.GetContentHash()); using (var stream = SerializableBytes.CreateWritableStream()) { using (var objectWriter = new ObjectWriter(stream, leaveOpen: true)) { serializer.Serialize(serializableSourceText, objectWriter, CancellationToken.None); } stream.Position = 0; using var objectReader = ObjectReader.TryGetReader(stream); var newText = (SerializableSourceText)serializer.Deserialize(serializableSourceText.GetWellKnownSynchronizationKind(), objectReader, CancellationToken.None); Assert.Equal(sourceText.ToString(), newText.GetText(CancellationToken.None).ToString()); } // test with wrong encoding that doesn't support serialization sourceText = SourceText.From("Hello", new NotSerializableEncoding()); serializableSourceText = new SerializableSourceText(sourceText, sourceText.GetContentHash()); using (var stream = SerializableBytes.CreateWritableStream()) { using (var objectWriter = new ObjectWriter(stream, leaveOpen: true)) { serializer.Serialize(serializableSourceText, objectWriter, CancellationToken.None); } stream.Position = 0; using var objectReader = ObjectReader.TryGetReader(stream); var newText = (SerializableSourceText)serializer.Deserialize(serializableSourceText.GetWellKnownSynchronizationKind(), objectReader, CancellationToken.None); Assert.Equal(sourceText.ToString(), newText.GetText(CancellationToken.None).ToString()); } } [Fact] public void TestCompilationOptions_NullableAndImport() { var csharpOptions = CSharp.CSharpCompilation.Create("dummy").Options.WithNullableContextOptions(NullableContextOptions.Warnings).WithMetadataImportOptions(MetadataImportOptions.All); var vbOptions = VisualBasic.VisualBasicCompilation.Create("dummy").Options.WithMetadataImportOptions(MetadataImportOptions.Internal); using var workspace = CreateWorkspace(); var serializer = workspace.Services.GetService<ISerializerService>(); VerifyOptions(csharpOptions); VerifyOptions(vbOptions); void VerifyOptions(CompilationOptions originalOptions) { using var stream = SerializableBytes.CreateWritableStream(); using (var objectWriter = new ObjectWriter(stream, leaveOpen: true)) { serializer.Serialize(originalOptions, objectWriter, CancellationToken.None); } stream.Position = 0; using var objectReader = ObjectReader.TryGetReader(stream); var recoveredOptions = (CompilationOptions)serializer.Deserialize(originalOptions.GetWellKnownSynchronizationKind(), objectReader, CancellationToken.None); var original = serializer.CreateChecksum(originalOptions, CancellationToken.None); var recovered = serializer.CreateChecksum(recoveredOptions, CancellationToken.None); Assert.Equal(original, recovered); } } private static SolutionAsset CloneAsset(ISerializerService serializer, SolutionAsset asset) { using var stream = SerializableBytes.CreateWritableStream(); using (var writer = new ObjectWriter(stream, leaveOpen: true)) { serializer.Serialize(asset.Value, writer, CancellationToken.None); } stream.Position = 0; using var reader = ObjectReader.TryGetReader(stream); var recovered = serializer.Deserialize(asset.Kind, reader, CancellationToken.None); var checksum = recovered is SerializableSourceText text ? text.ContentChecksum : serializer.CreateChecksum(recovered, CancellationToken.None); var assetFromStorage = new SolutionAsset(checksum, recovered); Assert.Equal(asset.Checksum, assetFromStorage.Checksum); return assetFromStorage; } private static AnalyzerFileReference CreateShadowCopiedAnalyzerReference(TempRoot tempRoot) { // use 2 different files as shadow copied content var original = typeof(AdhocWorkspace).Assembly.Location; var shadow = tempRoot.CreateFile("shadow", "dll"); shadow.CopyContentFrom(typeof(object).Assembly.Location); return new AnalyzerFileReference(original, new MockShadowCopyAnalyzerAssemblyLoader(ImmutableDictionary<string, string>.Empty.Add(original, shadow.Path))); } private sealed class MissingAnalyzerLoader() : IAnalyzerAssemblyLoader { public void AddDependencyLocation(string fullPath) { } public Assembly LoadFromPath(string fullPath) => throw new FileNotFoundException(fullPath); } private sealed class MissingMetadataReference : PortableExecutableReference { public MissingMetadataReference() : base(MetadataReferenceProperties.Assembly, "missing_reference", XmlDocumentationProvider.Default) { } protected override DocumentationProvider CreateDocumentationProvider() => null; protected override Metadata GetMetadataImpl() => throw new FileNotFoundException("can't find"); protected override PortableExecutableReference WithPropertiesImpl(MetadataReferenceProperties properties) => this; } private sealed class MockShadowCopyAnalyzerAssemblyLoader : IAnalyzerAssemblyLoader { private readonly ImmutableDictionary<string, string> _map; public MockShadowCopyAnalyzerAssemblyLoader(ImmutableDictionary<string, string> map) => _map = map; public void AddDependencyLocation(string fullPath) { } public Assembly LoadFromPath(string fullPath) => Assembly.LoadFrom(_map[fullPath]); } private sealed class NotSerializableEncoding : Encoding { private readonly Encoding _real = Encoding.UTF8; public override string WebName => _real.WebName; public override int GetByteCount(char[] chars, int index, int count) => _real.GetByteCount(chars, index, count); public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) => GetBytes(chars, charIndex, charCount, bytes, byteIndex); public override int GetCharCount(byte[] bytes, int index, int count) => GetCharCount(bytes, index, count); public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) => GetChars(bytes, byteIndex, byteCount, chars, charIndex); public override int GetMaxByteCount(int charCount) => GetMaxByteCount(charCount); public override int GetMaxCharCount(int byteCount) => GetMaxCharCount(byteCount); } }