File: BraceHighlighting\MultiCharacterBraceHighlightingTests.cs
Web Access
Project: src\src\EditorFeatures\TestUtilities\Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities.csproj (Microsoft.CodeAnalysis.EditorFeatures.Test.Utilities)
// 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.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.BraceMatching;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.CodeAnalysis.Text;
using Microsoft.CodeAnalysis.UnitTests;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.UnitTests.BraceHighlighting;
 
[Trait(Traits.Feature, Traits.Features.BraceHighlighting)]
public sealed class MultiCharacterBraceHighlightingTests : AbstractBraceHighlightingTests
{
    protected override EditorTestWorkspace CreateWorkspace(string markup, ParseOptions options)
        => EditorTestWorkspace.Create(
            NoCompilationConstants.LanguageName, compilationOptions: null, parseOptions: options, content: markup);
 
    internal override IBraceMatchingService GetBraceMatchingService(EditorTestWorkspace workspace)
        => new TestBraceMatchingService();
 
    private sealed class TestBraceMatchingService : IBraceMatchingService
    {
        public async Task<BraceMatchingResult?> GetMatchingBracesAsync(
            Document document, int position, BraceMatchingOptions options, CancellationToken cancellationToken)
        {
            var text = (await document.GetTextAsync(cancellationToken)).ToString();
            var braces = GetMatchingBraces(text, position);
            if (braces.HasValue)
            {
                Debug.Assert(text.Substring(braces.Value.LeftSpan.Start, braces.Value.LeftSpan.Length) == "<@");
                Debug.Assert(text.Substring(braces.Value.RightSpan.Start, braces.Value.RightSpan.Length) == "@>");
            }
 
            return braces;
        }
 
        public static BraceMatchingResult? GetMatchingBraces(
            string text, int position)
        {
            if (position < text.Length)
            {
                var ch = text[position];
 
                // Look for   <@   @>  depending on where the caret is.
 
                //      ^<@     @>
                if (ch == '<')
                {
                    Debug.Assert(text[position + 1] == '@');
                    var secondAt = text.IndexOf('@', position + 2);
                    return new BraceMatchingResult(new TextSpan(position, 2), new TextSpan(secondAt, 2));
                }
 
                //  <^@    @>     or   <@    ^@>
                if (ch == '@')
                {
                    if (text[position - 1] == '<')
                    {
                        var secondAt = text.IndexOf('@', position + 1);
                        return new BraceMatchingResult(new TextSpan(position - 1, 2), new TextSpan(secondAt, 2));
                    }
                    else
                    {
                        Debug.Assert(text[position + 1] == '>');
                        var lessThan = text.LastIndexOf('<', position);
                        return new BraceMatchingResult(new TextSpan(lessThan, 2), new TextSpan(position, 2));
                    }
                }
 
                // <@    @^>
                if (ch == '>')
                {
                    Debug.Assert(text[position - 1] == '@');
                    var lessThan = text.LastIndexOf('<', position);
                    return new BraceMatchingResult(new TextSpan(lessThan, 2), new TextSpan(position - 1, 2));
                }
            }
 
            return null;
        }
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotOnBrace()
    {
        await TestBraceHighlightingAsync(
"$$ <@    @>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestOnLeftOfStartBrace()
    {
        await TestBraceHighlightingAsync(
"$$[|<@|]    [|@>|]");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestInsideStartBrace()
    {
        await TestBraceHighlightingAsync(
"[|<$$@|]    [|@>|]");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotOnRightOfStartBrace()
    {
        await TestBraceHighlightingAsync(
"<@$$    @>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotOnLeftOfCloseBrace()
    {
        await TestBraceHighlightingAsync(
"<@    $$@>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestInsideCloseBrace()
    {
        await TestBraceHighlightingAsync(
"[|<@|]    [|@$$>|]");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestOnRightOfCloseBrace()
    {
        await TestBraceHighlightingAsync(
"[|<@|]    [|@>$$|]");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotAfterBrace()
    {
        await TestBraceHighlightingAsync(
"<@    @> $$");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotOnBrace2()
    {
        await TestBraceHighlightingAsync(
"$$ <@    @><@    @>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestOnLeftOfStartBrace2()
    {
        await TestBraceHighlightingAsync(
"$$[|<@|]    [|@>|]<@    @>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestInsideStartBrace2()
    {
        await TestBraceHighlightingAsync(
"[|<$$@|]    [|@>|]<@    @>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotOnRightOfStartBrace2()
    {
        await TestBraceHighlightingAsync(
"<@$$    @><@    @>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotOnLeftOfCloseBrace2()
    {
        await TestBraceHighlightingAsync(
"<@    $$@><@    @>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestInsideCloseBrace3()
    {
        await TestBraceHighlightingAsync(
"[|<@|]    [|@$$>|]<@    @>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestOnRightOfCloseBrace2()
    {
        await TestBraceHighlightingAsync(
"[|<@|]    [|@>|]$$[|<@|]    [|@>|]");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestInSecondBracePair()
    {
        await TestBraceHighlightingAsync(
"<@    @>[|<$$@|]    [|@>|]");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotAfterSecondBracePairStart()
    {
        await TestBraceHighlightingAsync(
"<@    @><@$$    @>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotBeforeSecondBracePairEnd()
    {
        await TestBraceHighlightingAsync(
"<@    @><@    $$@>");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestInSecondBracePairEnd()
    {
        await TestBraceHighlightingAsync(
"<@    @>[|<@|]    [|@$$>|]");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestAtSecondBracePairEnd()
    {
        await TestBraceHighlightingAsync(
"<@    @>[|<@|]    [|@>|]$$");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/18050")]
    public async Task TestNotAfterSecondBracePairEnd()
    {
        await TestBraceHighlightingAsync(
"<@    @><@    @>  $$");
    }
}