File: AutomaticCompletion\AbstractAutomaticBraceCompletionTests.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;
using System.Linq;
using Microsoft.CodeAnalysis.AutomaticCompletion;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.BraceCompletion;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.UnitTests.AutomaticCompletion
{
    [UseExportProvider]
    public abstract class AbstractAutomaticBraceCompletionTests
    {
        internal static void CheckStart(IBraceCompletionSession session, bool expectValidSession = true)
        {
            Type(session, session.OpeningBrace.ToString());
 
            session.Start();
 
            if (expectValidSession)
            {
                var closingPoint = session.ClosingPoint.GetPoint(session.SubjectBuffer.CurrentSnapshot).Subtract(1);
                Assert.Equal(closingPoint.GetChar(), session.ClosingBrace);
            }
            else
            {
                Assert.Null(session.OpeningPoint);
                Assert.Null(session.ClosingPoint);
            }
        }
 
        internal static void CheckBackspace(IBraceCompletionSession session)
        {
            session.TextView.TryMoveCaretToAndEnsureVisible(session.OpeningPoint.GetPoint(session.SubjectBuffer.CurrentSnapshot).Add(1));
            session.PreBackspace(out var handled);
            if (!handled)
            {
                session.PostBackspace();
            }
 
            Assert.Null(session.OpeningPoint);
            Assert.Null(session.ClosingPoint);
        }
 
        internal static void CheckTab(IBraceCompletionSession session, bool allowTab = true)
        {
            session.PreTab(out var handled);
            if (!handled)
            {
                session.PostTab();
            }
 
            var caret = session.TextView.GetCaretPoint(session.SubjectBuffer).Value;
            if (allowTab)
            {
                Assert.Equal(session.ClosingPoint.GetPosition(session.SubjectBuffer.CurrentSnapshot), caret.Position);
            }
            else
            {
                Assert.True(caret.Position < session.ClosingPoint.GetPosition(session.SubjectBuffer.CurrentSnapshot));
            }
        }
 
        internal static void CheckReturn(IBraceCompletionSession session, int indentation, string result = null)
        {
            session.PreReturn(out var handled);
 
            Type(session, Environment.NewLine);
 
            if (!handled)
            {
                session.PostReturn();
            }
 
            var virtualCaret = session.TextView.GetVirtualCaretPoint(session.SubjectBuffer).Value;
            Assert.True(indentation == virtualCaret.VirtualSpaces, $"Expected indentation was {indentation}, but the actual indentation was {virtualCaret.VirtualSpaces}");
 
            if (result != null)
            {
                AssertEx.EqualOrDiff(result, session.SubjectBuffer.CurrentSnapshot.GetText());
            }
        }
 
        internal static void CheckText(IBraceCompletionSession session, string result)
            => Assert.Equal(result, session.SubjectBuffer.CurrentSnapshot.GetText());
 
        internal static void CheckReturnOnNonEmptyLine(IBraceCompletionSession session, int expectedVirtualSpace)
        {
            session.PreReturn(out var handled);
 
            Type(session, Environment.NewLine);
 
            if (!handled)
            {
                session.PostReturn();
            }
 
            var virtualCaret = session.TextView.GetVirtualCaretPoint(session.SubjectBuffer).Value;
            Assert.Equal(expectedVirtualSpace, virtualCaret.VirtualSpaces);
        }
 
        internal static void CheckOverType(IBraceCompletionSession session, bool allowOverType = true)
        {
            var preClosingPoint = session.ClosingPoint.GetPoint(session.SubjectBuffer.CurrentSnapshot);
            Assert.Equal(session.ClosingBrace, preClosingPoint.Subtract(1).GetChar());
            session.PreOverType(out var handled);
            if (!handled)
            {
                session.PostOverType();
            }
 
            var postClosingPoint = session.ClosingPoint.GetPoint(session.SubjectBuffer.CurrentSnapshot);
            Assert.Equal(postClosingPoint.Subtract(1).GetChar(), session.ClosingBrace);
 
            var caret = session.TextView.GetCaretPoint(session.SubjectBuffer).Value;
            if (allowOverType)
            {
                Assert.Equal(postClosingPoint.Position, caret.Position);
            }
            else
            {
                Assert.True(caret.Position < postClosingPoint.Position);
            }
        }
 
        internal static void Type(IBraceCompletionSession session, string text)
        {
            var buffer = session.SubjectBuffer;
            var caret = session.TextView.GetCaretPoint(buffer).Value;
 
            using var edit = buffer.CreateEdit();
            edit.Insert(caret.Position, text);
            edit.Apply();
        }
 
        internal static Holder CreateSession(EditorTestWorkspace workspace, char opening, char closing, OptionsCollection globalOptions = null)
        {
            workspace.SetAnalyzerFallbackAndGlobalOptions(globalOptions);
 
            var document = workspace.Documents.First();
 
            var provider = Assert.IsType<BraceCompletionSessionProvider>(workspace.GetService<IBraceCompletionSessionProvider>());
 
            var openingPoint = new SnapshotPoint(document.GetTextBuffer().CurrentSnapshot, document.CursorPosition.Value);
            var textView = document.GetTextView();
 
            workspace.GlobalOptions.SetEditorOptions(textView.Options.GlobalOptions, document.Project.Language);
 
            if (provider.TryCreateSession(textView, openingPoint, opening, closing, out var session))
            {
                return new Holder(workspace, session);
            }
 
            workspace.Dispose();
            return null;
        }
 
        internal class Holder : IDisposable
        {
            public EditorTestWorkspace Workspace { get; }
            public IBraceCompletionSession Session { get; }
 
            public Holder(EditorTestWorkspace workspace, IBraceCompletionSession session)
            {
                this.Workspace = workspace;
                this.Session = session;
            }
 
            public void Dispose()
                => this.Workspace.Dispose();
        }
    }
}