File: RazorLanguageService_IVsLanguageDebugInfoTest.cs
Web Access
Project: src\src\Razor\src\Razor\test\Microsoft.VisualStudio.LanguageServices.Razor.UnitTests\Microsoft.VisualStudio.LanguageServices.Razor.UnitTests.csproj (Microsoft.VisualStudio.LanguageServices.Razor.UnitTests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
#nullable disable
 
using System;
using System.Collections.Generic;
using System.Threading;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.AspNetCore.Razor.Test.Common.Editor;
using Microsoft.VisualStudio.Editor;
using Microsoft.VisualStudio.Razor.Debugging;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Utilities;
using Moq;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.VisualStudio.Razor;
 
public class RazorLanguageService_IVsLanguageDebugInfoTest(ITestOutputHelper testOutput) : ToolingTestBase(testOutput)
{
    private readonly TextSpan[] _textSpans = [new TextSpan()];
 
    [Fact]
    public void ValidateBreakpointLocation_CanNotGetBackingTextBuffer_ReturnsNotImpl()
    {
        // Arrange
        var editorAdaptersFactoryService = new Mock<IVsEditorAdaptersFactoryService>(MockBehavior.Strict);
        editorAdaptersFactoryService.Setup(s => s.GetDataBuffer(It.IsAny<IVsTextBuffer>())).Returns(value: null);
        var languageService = CreateLanguageServiceWith(editorAdaptersFactory: editorAdaptersFactoryService.Object);
 
        // Act
        var result = languageService.ValidateBreakpointLocation(StrictMock.Of<IVsTextBuffer>(), 0, 0, _textSpans);
 
        // Assert
        Assert.Equal(VSConstants.E_NOTIMPL, result);
    }
 
    [Fact]
    public void ValidateBreakpointLocation_InvalidLocation_ReturnsEFail()
    {
        // Arrange
        var languageService = CreateLanguageServiceWith();
 
        // Act
        var result = languageService.ValidateBreakpointLocation(StrictMock.Of<IVsTextBuffer>(), int.MaxValue, 0, _textSpans);
 
        // Assert
        Assert.Equal(VSConstants.E_FAIL, result);
    }
 
    [Fact]
    public void ValidateBreakpointLocation_NullBreakpointRange_ReturnsEFail()
    {
        // Arrange
        var languageService = CreateLanguageServiceWith();
 
        // Act
        var result = languageService.ValidateBreakpointLocation(StrictMock.Of<IVsTextBuffer>(), 0, 0, _textSpans);
 
        // Assert
        Assert.Equal(VSConstants.E_FAIL, result);
    }
 
    [Fact]
    public void ValidateBreakpointLocation_ValidBreakpointRange_ReturnsSOK()
    {
        // Arrange
        var breakpointRange = LspFactory.CreateRange(2, 4, 3, 5);
        var breakpointResolver = new MockRepository(MockBehavior.Strict).OneOf<IRazorBreakpointResolver>(resolver => resolver.TryResolveBreakpointRangeAsync(It.IsAny<ITextBuffer>(), 0, 0, It.IsAny<CancellationToken>()) == System.Threading.Tasks.Task.FromResult(breakpointRange));
        var languageService = CreateLanguageServiceWith(breakpointResolver);
 
        // Act
        var result = languageService.ValidateBreakpointLocation(StrictMock.Of<IVsTextBuffer>(), 0, 0, _textSpans);
 
        // Assert
        Assert.Equal(VSConstants.S_OK, result);
        var span = Assert.Single(_textSpans);
        Assert.Equal(2, span.iStartLine);
        Assert.Equal(4, span.iStartIndex);
        Assert.Equal(3, span.iEndLine);
        Assert.Equal(5, span.iEndIndex);
    }
 
    [Fact]
    public void ValidateBreakpointLocation_CanNotCreateDialog_ReturnsEFail()
    {
        // Arrange
        var uiThreadExecutor = new Mock<IUIThreadOperationExecutor>(MockBehavior.Strict);
        uiThreadExecutor.Setup(f => f.Execute(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<Action<IUIThreadOperationContext>>())).Returns(value: UIThreadOperationStatus.Canceled);
        var languageService = CreateLanguageServiceWith(uiThreadOperationExecutor: uiThreadExecutor.Object);
 
        // Act
        var result = languageService.ValidateBreakpointLocation(StrictMock.Of<IVsTextBuffer>(), 0, 0, _textSpans);
 
        // Assert
        Assert.Equal(VSConstants.E_FAIL, result);
    }
 
    [Fact]
    public void GetProximityExpressions_CanNotGetBackingTextBuffer_ReturnsNotImpl()
    {
        // Arrange
        var editorAdaptersFactoryService = new Mock<IVsEditorAdaptersFactoryService>(MockBehavior.Strict);
        editorAdaptersFactoryService.Setup(s => s.GetDataBuffer(It.IsAny<IVsTextBuffer>())).Returns(value: null);
        var languageService = CreateLanguageServiceWith(editorAdaptersFactory: editorAdaptersFactoryService.Object);
 
        // Act
        var result = languageService.GetProximityExpressions(StrictMock.Of<IVsTextBuffer>(), 0, 0, 0, out _);
 
        // Assert
        Assert.Equal(VSConstants.E_NOTIMPL, result);
    }
 
    [Fact]
    public void GetProximityExpressions_InvalidLocation_ReturnsEFail()
    {
        // Arrange
        var languageService = CreateLanguageServiceWith();
 
        // Act
        var result = languageService.GetProximityExpressions(StrictMock.Of<IVsTextBuffer>(), int.MaxValue, 0, 0, out _);
 
        // Assert
        Assert.Equal(VSConstants.E_FAIL, result);
    }
 
    [Fact]
    public void GetProximityExpressions_NullRange_ReturnsEFail()
    {
        // Arrange
        var languageService = CreateLanguageServiceWith();
 
        // Act
        var result = languageService.GetProximityExpressions(StrictMock.Of<IVsTextBuffer>(), 0, 0, 0, out _);
 
        // Assert
        Assert.Equal(VSConstants.E_FAIL, result);
    }
 
    [Fact]
    public void GetProximityExpressions_ValidRange_ReturnsSOK()
    {
        // Arrange
        IReadOnlyList<string> expressions = new[] { "something" };
        var resolver = new MockRepository(MockBehavior.Strict).OneOf<IRazorProximityExpressionResolver>(resolver => resolver.TryResolveProximityExpressionsAsync(It.IsAny<ITextBuffer>(), 0, 0, It.IsAny<CancellationToken>()) == System.Threading.Tasks.Task.FromResult(expressions));
        var languageService = CreateLanguageServiceWith(proximityExpressionResolver: resolver);
 
        // Act
        var result = languageService.GetProximityExpressions(StrictMock.Of<IVsTextBuffer>(), 0, 0, 0, out var resolvedExpressions);
 
        // Assert
        Assert.Equal(VSConstants.S_OK, result);
        var concreteResolvedExpressions = Assert.IsType<VsEnumBSTR>(resolvedExpressions);
        Assert.Equal(expressions, concreteResolvedExpressions.Values);
    }
 
    [Fact]
    public void GetProximityExpressions_CanNotCreateDialog_ReturnsEFail()
    {
        // Arrange
        var uiThreadOperationExecutor = new Mock<IUIThreadOperationExecutor>(MockBehavior.Strict);
        uiThreadOperationExecutor.Setup(f => f.Execute(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>(), It.IsAny<bool>(), It.IsAny<Action<IUIThreadOperationContext>>())).Returns(UIThreadOperationStatus.Canceled);
        var languageService = CreateLanguageServiceWith(uiThreadOperationExecutor: uiThreadOperationExecutor.Object);
 
        // Act
        var result = languageService.GetProximityExpressions(StrictMock.Of<IVsTextBuffer>(), 0, 0, 0, out _);
 
        // Assert
        Assert.Equal(VSConstants.E_FAIL, result);
    }
 
    private RazorLanguageService CreateLanguageServiceWith(
        IRazorBreakpointResolver breakpointResolver = null,
        IRazorProximityExpressionResolver proximityExpressionResolver = null,
        IUIThreadOperationExecutor uiThreadOperationExecutor = null,
        IVsEditorAdaptersFactoryService editorAdaptersFactory = null)
    {
        if (breakpointResolver is null)
        {
            breakpointResolver = new Mock<IRazorBreakpointResolver>(MockBehavior.Strict).Object;
            Mock.Get(breakpointResolver)
                .Setup(r => r.TryResolveBreakpointRangeAsync(
                    It.IsAny<ITextBuffer>(),
                    It.IsAny<int>(),
                    It.IsAny<int>(),
                    It.IsAny<CancellationToken>()))
                .ReturnsAsync(value: null);
        }
 
        if (proximityExpressionResolver is null)
        {
            proximityExpressionResolver = new Mock<IRazorProximityExpressionResolver>(MockBehavior.Strict).Object;
            Mock.Get(proximityExpressionResolver)
                .Setup(r => r.TryResolveProximityExpressionsAsync(
                    It.IsAny<ITextBuffer>(),
                    It.IsAny<int>(),
                    It.IsAny<int>(),
                    It.IsAny<CancellationToken>()))
                .ReturnsAsync(value: null);
        }
 
        uiThreadOperationExecutor ??= new TestIUIThreadOperationExecutor();
        editorAdaptersFactory ??= new MockRepository(MockBehavior.Strict).OneOf<IVsEditorAdaptersFactoryService>(service => service.GetDataBuffer(It.IsAny<IVsTextBuffer>()) == new TestTextBuffer(new StringTextSnapshot(Environment.NewLine), /* contentType */ null));
 
        var lspServerActivationTracker = new LspServerActivationTracker();
        lspServerActivationTracker.Activated();
 
        var languageService = new RazorLanguageService(breakpointResolver, proximityExpressionResolver, lspServerActivationTracker, uiThreadOperationExecutor, editorAdaptersFactory, JoinableTaskFactory);
        return languageService;
    }
 
    private class TestIUIThreadOperationExecutor : IUIThreadOperationExecutor
    {
        public IUIThreadOperationContext BeginExecute(string title, string defaultDescription, bool allowCancellation, bool showProgress)
        {
            throw new NotImplementedException();
        }
 
        public IUIThreadOperationContext BeginExecute(UIThreadOperationExecutionOptions executionOptions)
        {
            throw new NotImplementedException();
        }
 
        public UIThreadOperationStatus Execute(string title, string defaultDescription, bool allowCancellation, bool showProgress, Action<IUIThreadOperationContext> action)
        {
            using (var context = new TestUIThreadOperationContext())
            {
                action(context);
            }
 
            return UIThreadOperationStatus.Completed;
        }
 
        public UIThreadOperationStatus Execute(UIThreadOperationExecutionOptions executionOptions, Action<IUIThreadOperationContext> action)
        {
            throw new NotImplementedException();
        }
 
        private class TestUIThreadOperationContext : IUIThreadOperationContext
        {
            public TestUIThreadOperationContext()
            {
            }
 
            public CancellationToken UserCancellationToken => new();
 
            public bool AllowCancellation => throw new NotImplementedException();
 
            public string Description => throw new NotImplementedException();
 
            public IEnumerable<IUIThreadOperationScope> Scopes => throw new NotImplementedException();
 
            public PropertyCollection Properties => throw new NotImplementedException();
 
            public IUIThreadOperationScope AddScope(bool allowCancellation, string description)
            {
                throw new NotImplementedException();
            }
 
            public void Dispose()
            {
            }
 
            public void TakeOwnership()
            {
                throw new NotImplementedException();
            }
        }
    }
}