File: Intents\IntentTestsBase.cs
Web Access
Project: src\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.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.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Editor.UnitTests;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.ExternalAccess.IntelliCode.Api;
using Microsoft.CodeAnalysis.Shared.Extensions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.Text.Shared.Extensions;
using Microsoft.VisualStudio.Text;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Intents;
 
public abstract class IntentTestsBase
{
    internal static async Task VerifyIntentMissingAsync(
        string intentName,
        string priorDocumentText,
        string currentDocumentText,
        OptionsCollection? options = null,
        string? intentData = null)
    {
        using var workspace = EditorTestWorkspace.CreateCSharp(priorDocumentText, composition: EditorTestCompositions.EditorFeatures);
        var results = await GetIntentsAsync(workspace, intentName, currentDocumentText, options, intentData).ConfigureAwait(false);
        Assert.Empty(results);
    }
 
    internal static Task VerifyExpectedTextAsync(
        string intentName,
        string priorDocumentText,
        string currentDocumentText,
        string expectedText,
        OptionsCollection? options = null,
        string? intentData = null)
    {
        return VerifyExpectedTextAsync(intentName, priorDocumentText, currentDocumentText, [], [expectedText], options, intentData);
    }
 
    internal static async Task VerifyExpectedTextAsync(
        string intentName,
        string priorDocumentText,
        string currentDocumentText,
        string[] additionalDocuments,
        string[] expectedTexts,
        OptionsCollection? options = null,
        string? intentData = null)
    {
        // Create the workspace from the prior document + any additional documents.
        var documentSet = additionalDocuments.Prepend(priorDocumentText).ToArray();
        using var workspace = EditorTestWorkspace.CreateCSharp(documentSet, composition: EditorTestCompositions.EditorFeatures);
        var results = await GetIntentsAsync(workspace, intentName, currentDocumentText, options, intentData).ConfigureAwait(false);
 
        // For now, we're just taking the first result to match intellicode behavior.
        var result = results.First();
 
        var actualDocumentTexts = new List<string>();
        foreach (var documentChange in result.DocumentChanges)
        {
            // Get the document and open it.  Since we're modifying the text buffer we don't care about linked documents.
            var documentBuffer = workspace.GetTestDocument(documentChange.Key)!.GetTextBuffer();
 
            using var edit = documentBuffer.CreateEdit();
            foreach (var change in documentChange.Value)
            {
                edit.Replace(change.Span.ToSpan(), change.NewText);
            }
 
            edit.Apply();
 
            actualDocumentTexts.Add(documentBuffer.CurrentSnapshot.GetText());
        }
 
        actualDocumentTexts.Sort();
        Array.Sort(expectedTexts);
 
        Assert.Equal(expectedTexts.Length, actualDocumentTexts.Count);
        for (var i = 0; i < actualDocumentTexts.Count; i++)
        {
            AssertEx.EqualOrDiff(expectedTexts[i], actualDocumentTexts[i]);
        }
    }
 
    internal static async Task<ImmutableArray<IntentSource>> GetIntentsAsync(
        EditorTestWorkspace workspace,
        string intentName,
        string currentDocumentText,
        OptionsCollection? options = null,
        string? intentData = null)
    {
        workspace.SetAnalyzerFallbackOptions(options);
 
        var intentSource = workspace.ExportProvider.GetExportedValue<IIntentSourceProvider>();
 
        // Get the prior test document from the workspace.
        var testDocument = workspace.Documents.Single(d => d.Name == "test1.cs");
        var priorDocument = workspace.CurrentSolution.GetRequiredDocument(testDocument.Id);
 
        // Extract the prior selection annotated region from the prior document.
        var priorSelection = testDocument.AnnotatedSpans["priorSelection"].Single();
 
        // Move the test document buffer forward to the current document.
        testDocument.Update(SourceText.From(currentDocumentText));
        var currentTextBuffer = testDocument.GetTextBuffer();
 
        // Get the text change to pass into the API that rewinds the current document to the prior document.
        var currentDocument = currentTextBuffer.CurrentSnapshot.GetOpenDocumentInCurrentContextWithChanges();
        var textDiffService = workspace.CurrentSolution.Services.GetRequiredService<IDocumentTextDifferencingService>();
        var changes = await textDiffService.GetTextChangesAsync(currentDocument, priorDocument, CancellationToken.None).ConfigureAwait(false);
 
        // Get the current snapshot span to pass in.
        var currentSnapshot = new SnapshotSpan(currentTextBuffer.CurrentSnapshot, new Span(0, currentTextBuffer.CurrentSnapshot.Length));
 
        var intentContext = new IntentRequestContext(
            intentName,
            currentSnapshot,
            changes,
            priorSelection,
            intentData: intentData);
        var results = await intentSource.ComputeIntentsAsync(intentContext, CancellationToken.None).ConfigureAwait(false);
        return results;
    }
}