File: LinkedFiles\LinkedFileDiffMergingEditorTests.cs
Web Access
Project: src\src\EditorFeatures\Test\Microsoft.CodeAnalysis.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.EditorFeatures.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeRefactorings;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.UnitTests.LinkedFiles;
 
public sealed class LinkedFileDiffMergingEditorTests : AbstractCodeActionTest
{
    private const string WorkspaceXml = """
        <Workspace>
            <Project Language="C#" CommonReferences="true" AssemblyName="CSProj" PreprocessorSymbols="Proj1">
                <Document FilePath = "C.cs"><![CDATA[public class [|C|]
        {
            public class D
            {
            }
        }]]></Document>
            </Project>
            <Project Language = "C#" CommonReferences="true" PreprocessorSymbols="Proj2">
                <Document IsLinkFile = "true" LinkAssemblyName="CSProj" LinkFilePath="C.cs"/>
            </Project>
        </Workspace>
        """;
 
    private const string s_expectedCode = """
        internal class C
        {
            private class D
            {
            }
        }
        """;
 
    protected internal override string GetLanguage()
        => LanguageNames.CSharp;
 
    protected override CodeRefactoringProvider CreateCodeRefactoringProvider(EditorTestWorkspace workspace, TestParameters parameters)
        => new TestCodeRefactoringProvider();
 
    [WpfFact]
    public async Task TestCodeActionPreviewAndApply()
    {
        // TODO: WPF required due to https://github.com/dotnet/roslyn/issues/46153
        using var workspace = EditorTestWorkspace.Create(WorkspaceXml, composition: EditorTestCompositions.EditorFeaturesWpf);
        var codeIssueOrRefactoring = await GetCodeRefactoringAsync(workspace, new TestParameters());
 
        await TestActionOnLinkedFiles(
            workspace,
            expectedText: s_expectedCode,
            action: codeIssueOrRefactoring.CodeActions[0].action,
            expectedPreviewContents: """
                internal class C
                {
                    private class D
                    {
                ...
                """);
    }
 
    [Fact]
    public async Task TestWorkspaceTryApplyChangesDirectCall()
    {
        using var workspace = EditorTestWorkspace.Create(WorkspaceXml);
        var solution = workspace.CurrentSolution;
 
        var documentId = workspace.Documents.Single(d => !d.IsLinkFile).Id;
        var text = await workspace.CurrentSolution.GetRequiredDocument(documentId).GetTextAsync();
 
        var linkedDocumentId = workspace.Documents.Single(d => d.IsLinkFile).Id;
        var linkedText = await workspace.CurrentSolution.GetRequiredDocument(linkedDocumentId).GetTextAsync();
 
        var textString = linkedText.ToString();
 
        var newSolution = solution
            .WithDocumentText(documentId, text.Replace(textString.IndexOf("public"), "public".Length, "internal"))
            .WithDocumentText(linkedDocumentId, linkedText.Replace(textString.LastIndexOf("public"), "public".Length, "private"));
 
        workspace.TryApplyChanges(newSolution);
 
        Assert.Equal(s_expectedCode, (await workspace.CurrentSolution.GetRequiredDocument(documentId).GetTextAsync()).ToString());
        Assert.Equal(s_expectedCode, (await workspace.CurrentSolution.GetRequiredDocument(linkedDocumentId).GetTextAsync()).ToString());
    }
 
    protected override ParseOptions GetScriptOptions()
        => throw new NotSupportedException();
 
    private sealed class TestCodeRefactoringProvider : CodeRefactoringProvider
    {
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var document = context.Document;
            var linkedDocument = document.Project.Solution.Projects.Single(p => p != document.Project).Documents.Single();
            var sourceText = await linkedDocument.GetTextAsync();
            var textString = sourceText.ToString();
 
            var newSolution = document.Project.Solution
                .WithDocumentText(document.Id, (await document.GetTextAsync()).Replace(textString.IndexOf("public"), "public".Length, "internal"))
                .WithDocumentText(linkedDocument.Id, sourceText.Replace(textString.LastIndexOf("public"), "public".Length, "private"));
 
            context.RegisterRefactoring(CodeAction.Create("Description", _ => Task.FromResult(newSolution)), context.Span);
        }
    }
}