|
// 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 Microsoft.VisualStudio.Text.Editor;
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);
// Disable responsive-completion so that we don't cancel our work in the event that brace completion is
// taking too long.
textView.Options.SetOptionValue(DefaultOptions.ResponsiveCompletionOptionId, false);
if (provider.TryCreateSession(textView, openingPoint, opening, closing, out var session))
{
return new Holder(workspace, session);
}
workspace.Dispose();
return null;
}
internal sealed class Holder(EditorTestWorkspace workspace, IBraceCompletionSession session) : IDisposable
{
public readonly EditorTestWorkspace Workspace = workspace;
public readonly IBraceCompletionSession Session = session;
public void Dispose()
=> this.Workspace.Dispose();
}
}
|