File: EditAndContinue\ActiveStatementTrackingServiceTests.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.
 
#nullable disable
 
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.EditAndContinue;
using Microsoft.CodeAnalysis.Contracts.EditAndContinue;
using Microsoft.CodeAnalysis.EditAndContinue.UnitTests;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Roslyn.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.CSharp.EditAndContinue.UnitTests;
 
[UseExportProvider]
public class ActiveStatementTrackingServiceTests
{
    [Theory, CombinatorialData]
    public async Task TrackingService_GetLatestSpansAsync(bool scheduleInitialTrackingBeforeOpenDoc)
    {
        var source1 = "class C { void F() => G(1); void G(int a) => System.Console.WriteLine(1); }";
        var source2 = "class D { }";
 
        using var workspace = new EditorTestWorkspace();
 
        var span11 = new LinePositionSpan(new LinePosition(0, 10), new LinePosition(0, 15));
        var span12 = new LinePositionSpan(new LinePosition(0, 20), new LinePosition(0, 25));
        var span21 = new LinePositionSpan(new LinePosition(0, 11), new LinePosition(0, 16));
        var span22 = new LinePositionSpan(new LinePosition(0, 21), new LinePosition(0, 26));
 
        var spanProvider = new MockActiveStatementSpanProvider();
 
        spanProvider.GetBaseActiveStatementSpansImpl = (_, documentIds) => ImmutableArray.Create(
            ImmutableArray.Create(
                new ActiveStatementSpan(new ActiveStatementId(0), span11, ActiveStatementFlags.NonLeafFrame),
                new ActiveStatementSpan(new ActiveStatementId(1), span12, ActiveStatementFlags.LeafFrame)),
            ImmutableArray<ActiveStatementSpan>.Empty);
 
        spanProvider.GetAdjustedActiveStatementSpansImpl = (document, _) => document.Name switch
        {
            "1.cs" => ImmutableArray.Create(
                new ActiveStatementSpan(new ActiveStatementId(0), span21, ActiveStatementFlags.NonLeafFrame),
                new ActiveStatementSpan(new ActiveStatementId(1), span22, ActiveStatementFlags.LeafFrame)),
            "2.cs" => ImmutableArray<ActiveStatementSpan>.Empty,
            _ => throw ExceptionUtilities.Unreachable()
        };
 
        var testDocument1 = new EditorTestHostDocument(text: source1, displayName: "1.cs", exportProvider: workspace.ExportProvider, filePath: "1.cs");
        var testDocument2 = new EditorTestHostDocument(text: source2, displayName: "2.cs", exportProvider: workspace.ExportProvider, filePath: "2.cs");
        workspace.AddTestProject(new EditorTestHostProject(workspace, documents: [testDocument1, testDocument2]));
 
        // opens the documents
        var textBuffer1 = testDocument1.GetTextBuffer();
        var textBuffer2 = testDocument2.GetTextBuffer();
 
        var solution = workspace.CurrentSolution;
        var project = solution.Projects.Single();
        var document1 = project.Documents.Single(d => d.Name == "1.cs");
        var document2 = project.Documents.Single(d => d.Name == "2.cs");
        var snapshot1 = textBuffer1.CurrentSnapshot;
        var snapshot2 = textBuffer2.CurrentSnapshot;
        Assert.Same(snapshot1, document1.GetTextSynchronously(CancellationToken.None).FindCorrespondingEditorTextSnapshot());
        Assert.Same(snapshot2, document2.GetTextSynchronously(CancellationToken.None).FindCorrespondingEditorTextSnapshot());
 
        var trackingSession = new ActiveStatementTrackingService.TrackingSession(workspace, spanProvider);
 
        if (scheduleInitialTrackingBeforeOpenDoc)
        {
            await trackingSession.TrackActiveSpansAsync(solution);
 
            var spans1 = trackingSession.Test_GetTrackingSpans();
            AssertEx.Equal(
            [
                $"V0 →←@[10..15): NonLeafFrame",
                $"V0 →←@[20..25): LeafFrame"
            ], spans1[document1.FilePath].Select(s => $"{s.Span}: {s.Flags}"));
 
            var spans2 = await trackingSession.GetSpansAsync(solution, document1.Id, document1.FilePath, CancellationToken.None);
            AssertEx.Equal(["(0,10)-(0,15)", "(0,20)-(0,25)"], spans2.Select(s => s.LineSpan.ToString()));
 
            var spans3 = await trackingSession.GetSpansAsync(solution, document2.Id, document2.FilePath, CancellationToken.None);
            Assert.Empty(spans3);
        }
 
        var spans4 = await trackingSession.GetAdjustedTrackingSpansAsync(document1, snapshot1, CancellationToken.None);
        AssertEx.Equal(
        [
            $"V0 →←@[11..16): NonLeafFrame",
            $"V0 →←@[21..26): LeafFrame"
        ], spans4.Select(s => $"{s.Span}: {s.Flags}"));
 
        AssertEx.Empty(await trackingSession.GetAdjustedTrackingSpansAsync(document2, snapshot2, CancellationToken.None));
 
        if (!scheduleInitialTrackingBeforeOpenDoc)
        {
            await trackingSession.TrackActiveSpansAsync(solution);
 
            var spans5 = trackingSession.Test_GetTrackingSpans();
            AssertEx.Equal(
            [
                $"V0 →←@[11..16): NonLeafFrame",
                $"V0 →←@[21..26): LeafFrame"
            ], spans5[document1.FilePath].Select(s => $"{s.Span}: {s.Flags}"));
        }
 
        // we are not able to determine active statements in a document:
        spanProvider.GetAdjustedActiveStatementSpansImpl = (_, _) => ImmutableArray<ActiveStatementSpan>.Empty;
 
        var spans6 = await trackingSession.GetAdjustedTrackingSpansAsync(document1, snapshot1, CancellationToken.None);
        AssertEx.Equal(
        [
            $"V0 →←@[11..16): NonLeafFrame",
            $"V0 →←@[21..26): LeafFrame"
        ], spans6.Select(s => $"{s.Span}: {s.Flags}"));
    }
}