File: Cohost\CohostDocumentSpellCheckEndpointTest.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.
 
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor;
using Microsoft.AspNetCore.Razor.Test.Common;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Test.Utilities;
using Xunit;
using Xunit.Abstractions;
 
namespace Microsoft.VisualStudio.Razor.LanguageClient.Cohost;
 
public class CohostDocumentSpellCheckEndpointTest(ITestOutputHelper testOutputHelper) : CohostEndpointTestBase(testOutputHelper)
{
    [Fact]
    public async Task Handle()
    {
        var input = """
            @page [|"this is csharp"|]
 
            <div>[|
 
                Eat more chickin.
 
            |]</div>
 
            <script>
                // no spell checking of script tags
                @([|"unless they contain csharp"|])
            </script>
 
            <style>
                // no spell checking of style tags
                @([|"unless they contain csharp"|])
            </style>
 
            @{ var [|x|] = [|"csharp"|];
 
            @*[| Eat more chickin. |]*@
 
            <div class="[|fush|]" />
 
            @code
            {
                void [|M|]()
                {
                    [|// Eat more chickin|]
                }
            }
            """;
 
        await VerifySpellCheckableRangesAsync(input);
    }
 
    [Fact]
    public async Task ComponentAttributes()
    {
        await VerifySpellCheckableRangesAsync(
            input: """
                <SurveyPrompt Title="[|Hello|][| there|]" />
                <SurveyPrompt @bind-Title="InputValue" />
            
                <form @onsubmit="DoSubmit" required></form>
            
                <input type="[|checkbox|]" checked></input>
            
                @code
                {
                    private string? [|InputValue|] { get; set; }
                }
            """,
            additionalFiles: [
                (FilePath("SurveyPrompt.razor"), """
                    @namespace SomeProject
                    
                    <div></div>
                    
                    @code
                    {
                        [Parameter]
                        public string Title { get; set; }
                    }
                    """)]);
    }
 
    private async Task VerifySpellCheckableRangesAsync(TestCode input, (string file, string contents)[]? additionalFiles = null)
    {
        var document = CreateProjectAndRazorDocument(input.Text, additionalFiles: additionalFiles);
        var sourceText = await document.GetTextAsync(DisposalToken);
 
        var endpoint = new CohostDocumentSpellCheckEndpoint(IncompatibleProjectService, RemoteServiceInvoker);
 
        var span = new LinePositionSpan(new(0, 0), new(sourceText.Lines.Count, 0));
 
        var result = await endpoint.GetTestAccessor().HandleRequestAsync(document, DisposalToken);
 
        Assert.NotNull(result);
        var ranges = result.First().Ranges.AssumeNotNull();
 
        // To make for easier test failure analysis, we convert the ranges back to the test input, so we can show a diff
        // rather than "Expected 23, got 53" and leave the developer to deal with what that means.
        // As a bonus, this also ensures the ranges array has the right number of elements (ie, multiple of 3)
        var absoluteRanges = new List<(int Start, int End)>();
        var absoluteStart = 0;
        for (var i = 0; i < ranges.Length; i += 3)
        {
            var kind = ranges[i];
            var start = ranges[i + 1];
            var length = ranges[i + 2];
 
            absoluteStart += start;
            absoluteRanges.Add((absoluteStart, absoluteStart + length));
            absoluteStart += length;
        }
 
        // Make sure the response is sorted correctly, or the IDE will complain
        Assert.True(absoluteRanges.SequenceEqual(absoluteRanges.OrderBy(r => r.Start)), "Results are not in order!");
 
        absoluteRanges.Reverse();
 
        var actual = input.Text;
        foreach (var (start, end) in absoluteRanges)
        {
            actual = actual.Insert(end, "|]").Insert(start, "[|");
        }
 
        AssertEx.EqualOrDiff(input.OriginalInput, actual);
    }
}