提交 8a130d08 编写于 作者: I Ivan Basov 提交者: GitHub

Integration tests (#18090)

CSharpInteractiveCommands, REPL Classification and REPL Intellisence integration tests
上级 3d21157a
......@@ -18,16 +18,14 @@ namespace Roslyn.VisualStudio.IntegrationTests
{
public abstract class AbstractEditorTest : AbstractIntegrationTest
{
protected readonly VisualStudioWorkspace_OutOfProc VisualStudioWorkspaceOutOfProc;
protected readonly Editor_OutOfProc Editor;
protected readonly string ProjectName = "TestProj";
protected AbstractEditorTest(VisualStudioInstanceFactory instanceFactory)
: base(instanceFactory)
: base(instanceFactory, visualStudio => visualStudio.Instance.Editor)
{
VisualStudioWorkspaceOutOfProc = VisualStudio.Instance.VisualStudioWorkspace;
Editor = VisualStudio.Instance.Editor;
Editor = (Editor_OutOfProc)TextViewWindow;
}
protected AbstractEditorTest(VisualStudioInstanceFactory instanceFactory, string solutionName)
......@@ -39,13 +37,12 @@ protected AbstractEditorTest(VisualStudioInstanceFactory instanceFactory, string
VisualStudioInstanceFactory instanceFactory,
string solutionName,
string projectTemplate)
: base(instanceFactory)
: base(instanceFactory, visualStudio => visualStudio.Instance.Editor)
{
VisualStudio.Instance.SolutionExplorer.CreateSolution(solutionName);
VisualStudio.Instance.SolutionExplorer.AddProject(ProjectName, projectTemplate, LanguageName);
VisualStudioWorkspaceOutOfProc = VisualStudio.Instance.VisualStudioWorkspace;
Editor = VisualStudio.Instance.Editor;
Editor = (Editor_OutOfProc)TextViewWindow;
// Winforms and XAML do not open text files on creation
// so these editor tasks will not work if that is the project template being used.
......@@ -59,9 +56,6 @@ protected AbstractEditorTest(VisualStudioInstanceFactory instanceFactory, string
protected abstract string LanguageName { get; }
protected void WaitForAsyncOperations(params string[] featuresToWaitFor)
=> VisualStudioWorkspaceOutOfProc.WaitForAsyncOperations(string.Join(";",featuresToWaitFor));
protected void ClearEditor()
=> SetUpEditor("$$");
......@@ -143,12 +137,6 @@ protected void DisableSuggestionMode()
protected void EnableSuggestionMode()
=> VisualStudioWorkspaceOutOfProc.SetUseSuggestionMode(true);
protected void InvokeCompletionList()
{
ExecuteCommand(WellKnownCommandNames.Edit_ListMembers);
WaitForAsyncOperations(FeatureAttribute.CompletionSet);
}
protected void InvokeSignatureHelp()
{
ExecuteCommand(WellKnownCommandNames.Edit_ParameterInfo);
......@@ -277,15 +265,6 @@ protected void VerifyTextDoesNotContain(string expectedText)
Assert.DoesNotContain(expectedText, editorText);
}
protected void VerifyCompletionItemExists(params string[] expectedItems)
{
var completionItems = Editor.GetCompletionItems();
foreach (var expectedItem in expectedItems)
{
Assert.Contains(expectedItem, completionItems);
}
}
protected void VerifyCompletionItemDoesNotExist(params string[] expectedItems)
{
var completionItems = Editor.GetCompletionItems();
......@@ -455,17 +434,5 @@ protected void InvokeNavigateToAndPressEnter(string text)
WaitForAsyncOperations(FeatureAttribute.NavigateTo);
Editor.NavigateToSendKeys("{ENTER}");
}
public void VerifyCurrentTokenType(string tokenType)
{
WaitForAsyncOperations(
FeatureAttribute.SolutionCrawler,
FeatureAttribute.DiagnosticService,
FeatureAttribute.Classification);
var actualTokenTypes = Editor.GetCurrentClassifications();
Assert.Equal(actualTokenTypes.Length, 1);
Assert.Contains(tokenType, actualTokenTypes[0]);
Assert.NotEqual("text", tokenType);
}
}
}
}
\ No newline at end of file
......@@ -2,8 +2,11 @@
using System;
using System.Threading;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.IntegrationTest.Utilities;
using Microsoft.VisualStudio.IntegrationTest.Utilities.Input;
using Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess;
using Xunit;
namespace Roslyn.VisualStudio.IntegrationTests
{
......@@ -11,15 +14,33 @@ namespace Roslyn.VisualStudio.IntegrationTests
public abstract class AbstractIntegrationTest : IDisposable
{
protected readonly VisualStudioInstanceContext VisualStudio;
protected readonly VisualStudioWorkspace_OutOfProc VisualStudioWorkspaceOutOfProc;
protected readonly TextViewWindow_OutOfProc TextViewWindow;
protected AbstractIntegrationTest(VisualStudioInstanceFactory instanceFactory)
protected AbstractIntegrationTest(
VisualStudioInstanceFactory instanceFactory,
Func<VisualStudioInstanceContext, TextViewWindow_OutOfProc> textViewWindowBuilder)
{
VisualStudio = instanceFactory.GetNewOrUsedInstance(SharedIntegrationHostFixture.RequiredPackageIds);
TextViewWindow = textViewWindowBuilder(VisualStudio);
VisualStudioWorkspaceOutOfProc = VisualStudio.Instance.VisualStudioWorkspace;
}
public void Dispose()
=> VisualStudio.Dispose();
public void VerifyCurrentTokenType(string tokenType)
{
WaitForAsyncOperations(
FeatureAttribute.SolutionCrawler,
FeatureAttribute.DiagnosticService,
FeatureAttribute.Classification);
var actualTokenTypes = TextViewWindow.GetCurrentClassifications();
Assert.Equal(actualTokenTypes.Length, 1);
Assert.Contains(tokenType, actualTokenTypes[0]);
Assert.NotEqual("text", tokenType);
}
protected void Wait(double seconds)
{
var timeout = TimeSpan.FromMilliseconds(seconds * 1000);
......@@ -40,5 +61,29 @@ protected KeyPress Alt(VirtualKey virtualKey)
protected void ExecuteCommand(string commandName, string argument = "")
=> VisualStudio.Instance.ExecuteCommand(commandName, argument);
protected void InvokeCompletionList()
{
ExecuteCommand(WellKnownCommandNames.Edit_ListMembers);
WaitForAsyncOperations(FeatureAttribute.CompletionSet);
}
protected void VerifyCompletionItemExists(params string[] expectedItems)
{
var completionItems = TextViewWindow.GetCompletionItems();
foreach (var expectedItem in expectedItems)
{
Assert.Contains(expectedItem, completionItems);
}
}
protected void VerifyCaretPosition(int expectedCaretPosition)
{
var position = TextViewWindow.GetCaretPosition();
Assert.Equal(expectedCaretPosition, position);
}
protected void WaitForAsyncOperations(params string[] featuresToWaitFor)
=> VisualStudioWorkspaceOutOfProc.WaitForAsyncOperations(string.Join(";", featuresToWaitFor));
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.IntegrationTest.Utilities;
using Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess;
using Xunit;
......@@ -16,9 +17,9 @@ public abstract class AbstractInteractiveWindowTest : AbstractIntegrationTest
protected readonly CSharpInteractiveWindow_OutOfProc InteractiveWindow;
protected AbstractInteractiveWindowTest(VisualStudioInstanceFactory instanceFactory)
: base(instanceFactory)
: base(instanceFactory, visualStudio => visualStudio.Instance.CSharpInteractiveWindow)
{
InteractiveWindow = VisualStudio.Instance.CSharpInteractiveWindow;
InteractiveWindow = (CSharpInteractiveWindow_OutOfProc)TextViewWindow;
ClearInteractiveWindow();
}
......@@ -39,6 +40,12 @@ protected void ClearReplText()
VisualStudio.Instance.ExecuteCommand(Edit_SelectionCancelCommand);
}
protected void DisableSuggestionMode()
=> VisualStudioWorkspaceOutOfProc.SetUseSuggestionMode(false);
protected void EnableSuggestionMode()
=> VisualStudioWorkspaceOutOfProc.SetUseSuggestionMode(true);
protected void Reset(bool waitForPrompt = true)
=> InteractiveWindow.Reset(waitForPrompt: true);
......@@ -53,6 +60,14 @@ protected void SendKeys(params object[] input)
protected void InsertCode(string text)
=> InteractiveWindow.InsertCode(text);
protected void PlaceCaret(string text, int charsOffset = 0)
=> InteractiveWindow.PlaceCaret(
text,
charsOffset: charsOffset,
occurrence: 0,
extendSelection: false,
selectBlock: false);
protected void VerifyLastReplOutput(string expectedReplOutput)
{
var lastReplOutput = InteractiveWindow.GetLastReplOutput();
......@@ -65,12 +80,6 @@ protected void VerifyLastReplInput(string expectedReplInput)
Assert.Equal(expectedReplInput, lastReplInput);
}
protected void VerifyCaretPosition(int expectedCaretPosition)
{
var position = InteractiveWindow.GetCaretPosition();
Assert.Equal(expectedCaretPosition, position);
}
protected void VerifyLastReplOutputContains(string expectedReplOutput)
{
var lastReplOutput = InteractiveWindow.GetLastReplOutput();
......@@ -115,4 +124,4 @@ protected void VerifyReplPromptConsistency(string prompt, string output)
protected void WaitForReplOutput(string outputText)
=> InteractiveWindow.WaitForReplOutput(outputText);
}
}
}
\ No newline at end of file
......@@ -14,7 +14,7 @@ namespace Roslyn.VisualStudio.IntegrationTests.CSharp
public class CSharpBuild : AbstractIntegrationTest
{
public CSharpBuild(VisualStudioInstanceFactory instanceFactory)
: base(instanceFactory)
: base(instanceFactory, _ => null)
{
VisualStudio.Instance.SolutionExplorer.CreateSolution(nameof(CSharpBuild));
VisualStudio.Instance.SolutionExplorer.AddProject("TestProj", WellKnownProjectTemplates.ConsoleApplication, LanguageNames.CSharp);
......
......@@ -2,7 +2,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.VisualStudio.IntegrationTest.Utilities;
using Microsoft.VisualStudio.IntegrationTest.Utilities.Common;
using Microsoft.VisualStudio.IntegrationTest.Utilities.Input;
using Roslyn.Test.Utilities;
using Xunit;
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.VisualStudio.IntegrationTest.Utilities;
using Microsoft.VisualStudio.IntegrationTest.Utilities.Input;
using Xunit;
namespace Roslyn.VisualStudio.IntegrationTests.CSharp
{
[Collection(nameof(SharedIntegrationHostFixture))]
public class CSharpReplClassification : AbstractInteractiveWindowTest
{
public CSharpReplClassification(VisualStudioInstanceFactory instanceFactory)
: base(instanceFactory)
{
}
[Fact]
public void VerifyColorOfSomeTokens()
{
InsertCode(@"using System.Console;
/// <summary>innertext
/// </summary>
/// <see cref=""System.Environment"" />
/// <!--comment-->
/// <![CDATA[cdata]]]]>&gt;
/// <typeparam name=""attribute"" />
public static void Main(string[] args)
{
WriteLine(""Hello World"");
}");
PlaceCaret("using");
VerifyCurrentTokenType(tokenType: "keyword");
PlaceCaret("{");
VerifyCurrentTokenType(tokenType: "punctuation");
PlaceCaret("Main");
VerifyCurrentTokenType(tokenType: "identifier");
PlaceCaret("Hello");
VerifyCurrentTokenType(tokenType: "string");
PlaceCaret("<summary", charsOffset: -1);
SendKeys(new KeyPress(VirtualKey.Right, ShiftState.Alt));
VerifyCurrentTokenType(tokenType: "xml doc comment - delimiter");
PlaceCaret("summary");
VerifyCurrentTokenType(tokenType: "xml doc comment - name");
PlaceCaret("innertext");
VerifyCurrentTokenType(tokenType: "xml doc comment - text");
PlaceCaret("!--");
VerifyCurrentTokenType(tokenType: "xml doc comment - delimiter");
PlaceCaret("comment");
VerifyCurrentTokenType(tokenType: "xml doc comment - comment");
PlaceCaret("CDATA");
VerifyCurrentTokenType(tokenType: "xml doc comment - delimiter");
PlaceCaret("cdata");
VerifyCurrentTokenType(tokenType: "xml doc comment - cdata section");
PlaceCaret("attribute");
VerifyCurrentTokenType(tokenType: "identifier");
PlaceCaret("Environment");
VerifyCurrentTokenType(tokenType: "class name");
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Shared.TestHooks;
using Microsoft.VisualStudio.IntegrationTest.Utilities;
using Microsoft.VisualStudio.IntegrationTest.Utilities.Input;
using Xunit;
namespace Roslyn.VisualStudio.IntegrationTests.CSharp
{
[Collection(nameof(SharedIntegrationHostFixture))]
public class CSharpReplIntellisense : AbstractInteractiveWindowTest
{
public CSharpReplIntellisense(VisualStudioInstanceFactory instanceFactory)
: base(instanceFactory)
{
VisualStudioWorkspaceOutOfProc.SetUseSuggestionMode(true);
}
[Fact]
public void VerifyCompletionListOnEmptyTextAtTopLevel()
{
InvokeCompletionList();
VerifyCompletionItemExists("var", "public", "readonly", "goto");
}
[Fact]
public void VerifySharpRCompletionList()
{
InsertCode("#r \"");
InvokeCompletionList();
VerifyCompletionItemExists("System");
}
[Fact]
public void VerifyCommitCompletionOnTopLevel()
{
InsertCode("pub");
InvokeCompletionList();
VerifyCompletionItemExists("public");
SendKeys(VirtualKey.Tab);
VerifyLastReplInput("public");
SendKeys(VirtualKey.Escape);
}
[Fact]
public void VerifyCompletionListForAmbiguousParsingCases()
{
InsertCode(@"class C { }
public delegate R Del<T, R>(T arg);
Del<C, System");
SendKeys(VirtualKey.Period);
WaitForAsyncOperations(FeatureAttribute.CompletionSet);
VerifyCompletionItemExists("ArgumentException");
}
[Fact]
public void VerifySharpLoadCompletionList()
{
InsertCode("#load \"");
InvokeCompletionList();
VerifyCompletionItemExists("C:");
}
[Fact]
public void VerifyNoCrashOnEnter()
{
VisualStudioWorkspaceOutOfProc.SetUseSuggestionMode(false);
SendKeys("#help", VirtualKey.Enter, VirtualKey.Enter);
}
[Fact]
public void VerifyCorrectIntellisenseSelectionOnEnter()
{
VisualStudioWorkspaceOutOfProc.SetUseSuggestionMode(false);
SendKeys("TimeSpan.FromMin");
SendKeys(VirtualKey.Enter, "(0d)", VirtualKey.Enter);
WaitForReplOutput("[00:00:00]");
}
[Fact]
public void VerifyCompletionListForLoadMembers()
{
using (var temporaryTextFile = new TemporaryTextFile(
"c.csx",
"int x = 2; class Complex { public int foo() { return 4; } }"))
{
temporaryTextFile.Create();
SubmitText(string.Format("#load \"{0}\"", temporaryTextFile.FullName));
InvokeCompletionList();
VerifyCompletionItemExists("x", "Complex");
SendKeys(VirtualKey.Escape);
}
}
}
}
\ No newline at end of file
......@@ -11,7 +11,7 @@ namespace Roslyn.VisualStudio.IntegrationTests.VisualBasic
public class BasicBuild : AbstractIntegrationTest
{
public BasicBuild(VisualStudioInstanceFactory instanceFactory)
: base(instanceFactory)
: base(instanceFactory, _=> null)
{
VisualStudio.Instance.SolutionExplorer.CreateSolution(nameof(BasicBuild));
VisualStudio.Instance.SolutionExplorer.AddProject("TestProj", WellKnownProjectTemplates.ConsoleApplication, LanguageNames.VisualBasic);
......
......@@ -33,6 +33,8 @@
<Compile Include="CSharp\CSharpInteractive.cs" />
<Compile Include="AbstractEditorTest.cs" />
<Compile Include="CSharp\CSharpInteractiveCommands.cs" />
<Compile Include="CSharp\CSharpReplClassification.cs" />
<Compile Include="CSharp\CSharpReplIntellisense.cs" />
<Compile Include="CSharp\CSharpQuickInfo.cs" />
<Compile Include="CSharp\CSharpNavigateTo.cs" />
<Compile Include="CSharp\CSharpSignatureHelp.cs" />
......
......@@ -16,14 +16,12 @@
using Microsoft.VisualStudio.IntegrationTest.Utilities.Common;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Operations;
using Microsoft.VisualStudio.TextManager.Interop;
namespace Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess
{
internal class Editor_InProc : InProcComponent
internal class Editor_InProc : TextViewWindow_InProc
{
private static readonly Guid IWpfTextViewId = new Guid("8C40265E-9FDB-4F54-A0FD-EBB72B7D0476");
......@@ -32,7 +30,7 @@ internal class Editor_InProc : InProcComponent
public static Editor_InProc Create()
=> new Editor_InProc();
private static IWpfTextView GetActiveTextView()
protected override IWpfTextView GetActiveTextView()
=> GetActiveTextViewHost().TextView;
private static IVsTextView GetActiveVsTextView()
......@@ -45,36 +43,6 @@ private static IVsTextView GetActiveVsTextView()
return vsTextView;
}
public string[] GetCurrentClassifications()
=> InvokeOnUIThread(() =>
{
IClassifier classifier = null;
try
{
var textView = GetActiveTextView();
var selectionSpan = textView.Selection.StreamSelectionSpan.SnapshotSpan;
if (selectionSpan.Length == 0)
{
var textStructureNavigatorSelectorService = GetComponentModelService<ITextStructureNavigatorSelectorService>();
selectionSpan = textStructureNavigatorSelectorService
.GetTextStructureNavigator(textView.TextBuffer)
.GetExtentOfWord(selectionSpan.Start).Span;
}
var classifierAggregatorService = GetComponentModelService<IViewClassifierAggregatorService>();
classifier = classifierAggregatorService.GetClassifier(textView);
var classifiedSpans = classifier.GetClassificationSpans(selectionSpan);
return classifiedSpans.Select(x => x.ClassificationType.Classification).ToArray();
}
finally
{
if (classifier is IDisposable classifierDispose)
{
classifierDispose.Dispose();
}
}
});
private static IWpfTextViewHost GetActiveTextViewHost()
{
// The active text view might not have finished composing yet, waiting for the application to 'idle'
......@@ -92,26 +60,9 @@ private static IWpfTextViewHost GetActiveTextViewHost()
/// <summary>
/// Non-blocking version of <see cref="ExecuteOnActiveView"/>
/// </summary>
private static void BeginInvokeExecuteOnActiveView(Action<IWpfTextView> action)
private void BeginInvokeExecuteOnActiveView(Action<IWpfTextView> action)
=> BeginInvokeOnUIThread(GetExecuteOnActionViewCallback(action));
private static void ExecuteOnActiveView(Action<IWpfTextView> action)
=> InvokeOnUIThread(GetExecuteOnActionViewCallback(action));
private static Action GetExecuteOnActionViewCallback(Action<IWpfTextView> action)
=> () =>
{
var view = GetActiveTextView();
action(view);
};
private static T ExecuteOnActiveView<T>(Func<IWpfTextView, T> action)
=> InvokeOnUIThread(() =>
{
var view = GetActiveTextView();
return action(view);
});
public string GetActiveBufferName()
{
return GetDTE().ActiveDocument.Name;
......@@ -146,15 +97,6 @@ public string GetCurrentLineText()
return line.GetText();
});
public int GetCaretPosition()
=> ExecuteOnActiveView(view =>
{
var subjectBuffer = view.GetBufferContainingCaret();
var bufferPosition = view.Caret.Position.BufferPosition;
return bufferPosition.Position;
});
public string GetLineTextBeforeCaret()
=> ExecuteOnActiveView(view =>
{
......@@ -194,122 +136,6 @@ public void MoveCaret(int position)
view.Caret.MoveTo(point);
});
public void PlaceCaret(string marker, int charsOffset, int occurrence, bool extendSelection, bool selectBlock)
=> ExecuteOnActiveView(view =>
{
var dte = GetDTE();
dte.Find.FindWhat = marker;
dte.Find.MatchCase = true;
dte.Find.MatchInHiddenText = true;
dte.Find.Target = EnvDTE.vsFindTarget.vsFindTargetCurrentDocument;
dte.Find.Action = EnvDTE.vsFindAction.vsFindActionFind;
var originalPosition = GetCaretPosition();
view.Caret.MoveTo(new Microsoft.VisualStudio.Text.SnapshotPoint(view.GetBufferContainingCaret().CurrentSnapshot, 0));
if (occurrence > 0)
{
var result = EnvDTE.vsFindResult.vsFindResultNotFound;
for (var i = 0; i < occurrence; i++)
{
result = dte.Find.Execute();
}
if (result != EnvDTE.vsFindResult.vsFindResultFound)
{
throw new Exception("Occurrence " + occurrence + " of marker '" + marker + "' not found in text: " + view.TextSnapshot.GetText());
}
}
else
{
var result = dte.Find.Execute();
if (result != EnvDTE.vsFindResult.vsFindResultFound)
{
throw new Exception("Marker '" + marker + "' not found in text: " + view.TextSnapshot.GetText());
}
}
if (charsOffset > 0)
{
for (var i = 0; i < charsOffset - 1; i++)
{
view.Caret.MoveToNextCaretPosition();
}
view.Selection.Clear();
}
if (charsOffset < 0)
{
// On the first negative charsOffset, move to anchor-point position, as if the user hit the LEFT key
view.Caret.MoveTo(new SnapshotPoint(view.TextSnapshot, view.Selection.AnchorPoint.Position.Position));
for (var i = 0; i < -charsOffset - 1; i++)
{
view.Caret.MoveToPreviousCaretPosition();
}
view.Selection.Clear();
}
if (extendSelection)
{
var newPosition = view.Selection.ActivePoint.Position.Position;
view.Selection.Select(new VirtualSnapshotPoint(view.TextSnapshot, originalPosition), new VirtualSnapshotPoint(view.TextSnapshot, newPosition));
view.Selection.Mode = selectBlock ? TextSelectionMode.Box : TextSelectionMode.Stream;
}
});
/// <remarks>
/// This method does not wait for async operations before
/// querying the editor
/// </remarks>
public string[] GetCompletionItems()
=> ExecuteOnActiveView(view =>
{
var broker = GetComponentModelService<ICompletionBroker>();
var sessions = broker.GetSessions(view);
if (sessions.Count != 1)
{
throw new InvalidOperationException($"Expected exactly one session in the completion list, but found {sessions.Count}");
}
var selectedCompletionSet = sessions[0].SelectedCompletionSet;
return selectedCompletionSet.Completions.Select(c => c.DisplayText).ToArray();
});
/// <remarks>
/// This method does not wait for async operations before
/// querying the editor
/// </remarks>
public string GetCurrentCompletionItem()
=> ExecuteOnActiveView(view =>
{
var broker = GetComponentModelService<ICompletionBroker>();
var sessions = broker.GetSessions(view);
if (sessions.Count != 1)
{
throw new InvalidOperationException($"Expected exactly one session in the completion list, but found {sessions.Count}");
}
var selectedCompletionSet = sessions[0].SelectedCompletionSet;
return selectedCompletionSet.SelectionStatus.Completion.DisplayText;
});
/// <remarks>
/// This method does not wait for async operations before
/// querying the editor
/// </remarks>
public bool IsCompletionActive()
=> ExecuteOnActiveView(view =>
{
var broker = GetComponentModelService<ICompletionBroker>();
return broker.IsCompletionActive(view);
});
/// <remarks>
/// This method does not wait for async operations before
/// querying the editor
......@@ -835,5 +661,10 @@ public string GetWinFormButtonPropertyValue(string buttonName, string propertyNa
public void Undo()
=> GetDTE().ExecuteCommand("Edit.Undo");
protected override ITextBuffer GetBufferContainingCaret(IWpfTextView view)
{
return view.GetBufferContainingCaret();
}
}
}
......@@ -3,6 +3,8 @@
using System;
using System.Threading.Tasks;
using Microsoft.VisualStudio.InteractiveWindow;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
namespace Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess
{
......@@ -12,7 +14,7 @@ namespace Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess
/// <remarks>
/// This object exists in the Visual Studio host and is marhsalled across the process boundary.
/// </remarks>
internal abstract class InteractiveWindow_InProc : InProcComponent
internal abstract class InteractiveWindow_InProc : TextViewWindow_InProc
{
private const string ResetCommand = "InteractiveConsole.Reset";
private const string CleanScreenCommand = "InteractiveConsole.ClearScreen";
......@@ -46,8 +48,8 @@ public bool IsInitializing
public string GetReplText()
=> _interactiveWindow.TextView.TextBuffer.CurrentSnapshot.GetText();
public int GetCaretPosition()
=> _interactiveWindow.TextView.Caret.Position.BufferPosition.Position;
protected override IWpfTextView GetActiveTextView()
=> _interactiveWindow.TextView;
/// <summary>
/// Gets the contents of the REPL window without the prompt text.
......@@ -213,5 +215,10 @@ private async Task WaitForReplOutputContainsAsync(string outputText)
await Task.Delay(50);
}
}
protected override ITextBuffer GetBufferContainingCaret(IWpfTextView view)
{
return _interactiveWindow.TextView.TextBuffer;
}
}
}
}
\ No newline at end of file
......@@ -88,7 +88,7 @@ public void CreateSolution(string solutionName, bool saveExistingSolutionIfExist
CloseSolution(saveExistingSolutionIfExists);
}
var solutionPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
string solutionPath = IntegrationHelper.CreateTemporaryPath();
IntegrationHelper.DeleteDirectoryRecursively(solutionPath);
dte.Solution.Create(solutionPath, solutionName);
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Microsoft.VisualStudio.Language.Intellisense;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Classification;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Operations;
namespace Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess
{
internal abstract class TextViewWindow_InProc : InProcComponent
{
/// <remarks>
/// This method does not wait for async operations before
/// querying the editor
/// </remarks>
public string[] GetCompletionItems()
=> ExecuteOnActiveView(view =>
{
var broker = GetComponentModelService<ICompletionBroker>();
var sessions = broker.GetSessions(view);
if (sessions.Count != 1)
{
throw new InvalidOperationException($"Expected exactly one session in the completion list, but found {sessions.Count}");
}
var selectedCompletionSet = sessions[0].SelectedCompletionSet;
return selectedCompletionSet.Completions.Select(c => c.DisplayText).ToArray();
});
/// <remarks>
/// This method does not wait for async operations before
/// querying the editor
/// </remarks>
public string GetCurrentCompletionItem()
=> ExecuteOnActiveView(view =>
{
var broker = GetComponentModelService<ICompletionBroker>();
var sessions = broker.GetSessions(view);
if (sessions.Count != 1)
{
throw new InvalidOperationException($"Expected exactly one session in the completion list, but found {sessions.Count}");
}
var selectedCompletionSet = sessions[0].SelectedCompletionSet;
return selectedCompletionSet.SelectionStatus.Completion.DisplayText;
});
/// <remarks>
/// This method does not wait for async operations before
/// querying the editor
/// </remarks>
public bool IsCompletionActive()
=> ExecuteOnActiveView(view =>
{
var broker = GetComponentModelService<ICompletionBroker>();
return broker.IsCompletionActive(view);
});
protected abstract ITextBuffer GetBufferContainingCaret(IWpfTextView view);
public string[] GetCurrentClassifications()
=> InvokeOnUIThread(() =>
{
IClassifier classifier = null;
try
{
var textView = GetActiveTextView();
var selectionSpan = textView.Selection.StreamSelectionSpan.SnapshotSpan;
if (selectionSpan.Length == 0)
{
var textStructureNavigatorSelectorService = GetComponentModelService<ITextStructureNavigatorSelectorService>();
selectionSpan = textStructureNavigatorSelectorService
.GetTextStructureNavigator(textView.TextBuffer)
.GetExtentOfWord(selectionSpan.Start).Span;
}
var classifierAggregatorService = GetComponentModelService<IViewClassifierAggregatorService>();
classifier = classifierAggregatorService.GetClassifier(textView);
var classifiedSpans = classifier.GetClassificationSpans(selectionSpan);
return classifiedSpans.Select(x => x.ClassificationType.Classification).ToArray();
}
finally
{
if (classifier is IDisposable classifierDispose)
{
classifierDispose.Dispose();
}
}
});
public void PlaceCaret(
string marker,
int charsOffset,
int occurrence,
bool extendSelection,
bool selectBlock)
=> ExecuteOnActiveView(view =>
{
var dte = GetDTE();
dte.Find.FindWhat = marker;
dte.Find.MatchCase = true;
dte.Find.MatchInHiddenText = true;
dte.Find.Target = EnvDTE.vsFindTarget.vsFindTargetCurrentDocument;
dte.Find.Action = EnvDTE.vsFindAction.vsFindActionFind;
var originalPosition = GetCaretPosition();
view.Caret.MoveTo(new SnapshotPoint(GetBufferContainingCaret(view).CurrentSnapshot, 0));
if (occurrence > 0)
{
var result = EnvDTE.vsFindResult.vsFindResultNotFound;
for (var i = 0; i < occurrence; i++)
{
result = dte.Find.Execute();
}
if (result != EnvDTE.vsFindResult.vsFindResultFound)
{
throw new Exception("Occurrence " + occurrence + " of marker '" + marker + "' not found in text: " + view.TextSnapshot.GetText());
}
}
else
{
var result = dte.Find.Execute();
if (result != EnvDTE.vsFindResult.vsFindResultFound)
{
throw new Exception("Marker '" + marker + "' not found in text: " + view.TextSnapshot.GetText());
}
}
if (charsOffset > 0)
{
for (var i = 0; i < charsOffset - 1; i++)
{
view.Caret.MoveToNextCaretPosition();
}
view.Selection.Clear();
}
if (charsOffset < 0)
{
// On the first negative charsOffset, move to anchor-point position, as if the user hit the LEFT key
view.Caret.MoveTo(new SnapshotPoint(view.TextSnapshot, view.Selection.AnchorPoint.Position.Position));
for (var i = 0; i < -charsOffset - 1; i++)
{
view.Caret.MoveToPreviousCaretPosition();
}
view.Selection.Clear();
}
if (extendSelection)
{
var newPosition = view.Selection.ActivePoint.Position.Position;
view.Selection.Select(new VirtualSnapshotPoint(view.TextSnapshot, originalPosition), new VirtualSnapshotPoint(view.TextSnapshot, newPosition));
view.Selection.Mode = selectBlock ? TextSelectionMode.Box : TextSelectionMode.Stream;
}
});
public int GetCaretPosition()
=> ExecuteOnActiveView(view =>
{
var subjectBuffer = GetBufferContainingCaret(view);
var bufferPosition = view.Caret.Position.BufferPosition;
return bufferPosition.Position;
});
protected T ExecuteOnActiveView<T>(Func<IWpfTextView, T> action)
=> InvokeOnUIThread(() =>
{
var view = GetActiveTextView();
return action(view);
});
protected void ExecuteOnActiveView(Action<IWpfTextView> action)
=> InvokeOnUIThread(GetExecuteOnActionViewCallback(action));
protected Action GetExecuteOnActionViewCallback(Action<IWpfTextView> action)
=> () =>
{
var view = GetActiveTextView();
action(view);
};
protected abstract IWpfTextView GetActiveTextView();
}
}
\ No newline at end of file
......@@ -77,6 +77,8 @@ public enum VirtualKey : byte
W = 0x57,
X = 0x58,
Y = 0x59,
Z = 0x5A
Z = 0x5A,
Period = 0xBE
}
}
......@@ -77,6 +77,11 @@ public static void DeleteDirectoryRecursively(string path)
}
}
public static string CreateTemporaryPath()
{
return Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
}
public static bool DetachThreadInput(uint idAttach, uint idAttachTo)
{
var success = NativeMethods.AttachThreadInput(idAttach, idAttachTo, false);
......
......@@ -9,7 +9,7 @@ public class CSharpInteractiveWindow_OutOfProc : InteractiveWindow_OutOfProc
public CSharpInteractiveWindow_OutOfProc(VisualStudioInstance visualStudioInstance)
: base(visualStudioInstance) { }
internal override InteractiveWindow_InProc CreateInProcComponent(VisualStudioInstance visualStudioInstance)
internal override TextViewWindow_InProc CreateInProcComponent(VisualStudioInstance visualStudioInstance)
=> CreateInProcComponent<CSharpInteractiveWindow_InProc>(visualStudioInstance);
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.VisualStudio.IntegrationTest.Utilities.Common;
using Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess;
......@@ -10,126 +9,114 @@ namespace Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess
/// <summary>
/// Provides a means of interacting with the Visual Studio editor by remoting calls into Visual Studio.
/// </summary>
public partial class Editor_OutOfProc : OutOfProcComponent
public partial class Editor_OutOfProc : TextViewWindow_OutOfProc
{
private readonly Editor_InProc _inProc;
private readonly Editor_InProc _editorInProc;
internal Editor_OutOfProc(VisualStudioInstance visualStudioInstance)
: base(visualStudioInstance)
{
_inProc = CreateInProcComponent<Editor_InProc>(visualStudioInstance);
_editorInProc = (Editor_InProc)_textViewWindowInProc;
}
internal override TextViewWindow_InProc CreateInProcComponent(VisualStudioInstance visualStudioInstance)
=> CreateInProcComponent<Editor_InProc>(visualStudioInstance);
public void Activate()
=> _inProc.Activate();
=> _editorInProc.Activate();
public string GetText()
=> _inProc.GetText();
=> _editorInProc.GetText();
public void SetText(string value)
=> _inProc.SetText(value);
=> _editorInProc.SetText(value);
public string GetCurrentLineText()
=> _inProc.GetCurrentLineText();
public int GetCaretPosition()
=> _inProc.GetCaretPosition();
=> _editorInProc.GetCurrentLineText();
public string GetLineTextBeforeCaret()
=> _inProc.GetLineTextBeforeCaret();
=> _editorInProc.GetLineTextBeforeCaret();
public string GetSelectedText()
=> _inProc.GetSelectedText();
=> _editorInProc.GetSelectedText();
public string GetLineTextAfterCaret()
=> _inProc.GetLineTextAfterCaret();
=> _editorInProc.GetLineTextAfterCaret();
public void MoveCaret(int position)
=> _inProc.MoveCaret(position);
public string[] GetCurrentClassifications()
=> _inProc.GetCurrentClassifications();
public void PlaceCaret(string marker, int charsOffset, int occurrence, bool extendSelection, bool selectBlock)
=> _inProc.PlaceCaret(marker, charsOffset, occurrence, extendSelection, selectBlock);
public string[] GetCompletionItems()
{
WaitForCompletionSet();
return _inProc.GetCompletionItems();
}
=> _editorInProc.MoveCaret(position);
public string GetCurrentCompletionItem()
{
WaitForCompletionSet();
return _inProc.GetCurrentCompletionItem();
return _editorInProc.GetCurrentCompletionItem();
}
public bool IsCompletionActive()
{
WaitForCompletionSet();
return _inProc.IsCompletionActive();
return _editorInProc.IsCompletionActive();
}
public bool IsSignatureHelpActive()
{
WaitForSignatureHelp();
return _inProc.IsSignatureHelpActive();
return _editorInProc.IsSignatureHelpActive();
}
public Signature[] GetSignatures()
{
WaitForSignatureHelp();
return _inProc.GetSignatures();
return _editorInProc.GetSignatures();
}
public Signature GetCurrentSignature()
{
WaitForSignatureHelp();
return _inProc.GetCurrentSignature();
return _editorInProc.GetCurrentSignature();
}
public string GetQuickInfo()
{
WaitForQuickInfo();
return _inProc.GetQuickInfo();
return _editorInProc.GetQuickInfo();
}
public void ShowLightBulb()
=> _inProc.ShowLightBulb();
=> _editorInProc.ShowLightBulb();
public void WaitForLightBulbSession()
=> _inProc.WaitForLightBulbSession();
=> _editorInProc.WaitForLightBulbSession();
public void DismissLightBulbSession()
=> _inProc.DismissLightBulbSession();
=> _editorInProc.DismissLightBulbSession();
public bool IsLightBulbSessionExpanded()
=> _inProc.IsLightBulbSessionExpanded();
=> _editorInProc.IsLightBulbSessionExpanded();
public string[] GetLightBulbActions()
=> _inProc.GetLightBulbActions();
=> _editorInProc.GetLightBulbActions();
public void ApplyLightBulbAction(string action, FixAllScope? fixAllScope, bool blockUntilComplete = true)
=> _inProc.ApplyLightBulbAction(action, fixAllScope, blockUntilComplete);
=> _editorInProc.ApplyLightBulbAction(action, fixAllScope, blockUntilComplete);
public bool IsCaretOnScreen()
=> _inProc.IsCaretOnScreen();
=> _editorInProc.IsCaretOnScreen();
public void AddWinFormButton(string buttonName)
=> _inProc.AddWinFormButton(buttonName);
=> _editorInProc.AddWinFormButton(buttonName);
public void DeleteWinFormButton(string buttonName)
=> _inProc.DeleteWinFormButton(buttonName);
=> _editorInProc.DeleteWinFormButton(buttonName);
public void EditWinFormButtonProperty(string buttonName, string propertyName, string propertyValue, string propertyTypeName = null)
=> _inProc.EditWinFormButtonProperty(buttonName, propertyName, propertyValue, propertyTypeName);
=> _editorInProc.EditWinFormButtonProperty(buttonName, propertyName, propertyValue, propertyTypeName);
public void EditWinFormButtonEvent(string buttonName, string eventName, string eventHandlerName)
=> _inProc.EditWinFormButtonEvent(buttonName, eventName, eventHandlerName);
=> _editorInProc.EditWinFormButtonEvent(buttonName, eventName, eventHandlerName);
public string GetWinFormButtonPropertyValue(string buttonName, string propertyName)
=> _inProc.GetWinFormButtonPropertyValue(buttonName, propertyName);
=> _editorInProc.GetWinFormButtonPropertyValue(buttonName, propertyName);
/// <summary>
/// Sends key strokes to the active editor in Visual Studio. Various types are supported by this method:
......@@ -143,24 +130,24 @@ public void SendKeys(params object[] keys)
}
public void MessageBox(string message)
=> _inProc.MessageBox(message);
=> _editorInProc.MessageBox(message);
public void VerifyDialog(string dialogName, bool isOpen)
=> _inProc.VerifyDialog(dialogName, isOpen);
=> _editorInProc.VerifyDialog(dialogName, isOpen);
public void PressDialogButton(string dialogAutomationName, string buttonAutomationName)
=> _inProc.PressDialogButton(dialogAutomationName, buttonAutomationName);
=> _editorInProc.PressDialogButton(dialogAutomationName, buttonAutomationName);
public void DialogSendKeys(string dialogAutomationName, string keys)
=> _inProc.DialogSendKeys(dialogAutomationName, keys);
=> _editorInProc.DialogSendKeys(dialogAutomationName, keys);
public void Undo()
=> _inProc.Undo();
=> _editorInProc.Undo();
public void NavigateToSendKeys(string keys)
=> _inProc.SendKeysToNavigateTo(keys);
=> _editorInProc.SendKeysToNavigateTo(keys);
public void WaitForActiveView(string viewName)
=> _inProc.WaitForActiveView(viewName);
=> _editorInProc.WaitForActiveView(viewName);
}
}
\ No newline at end of file
......@@ -7,67 +7,62 @@ namespace Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess
/// <summary>
/// Provides a means of interacting with the interactive window in the Visual Studio host.
/// </summary>
public abstract class InteractiveWindow_OutOfProc : OutOfProcComponent
public abstract class InteractiveWindow_OutOfProc : TextViewWindow_OutOfProc
{
private readonly InteractiveWindow_InProc _inProc;
private readonly InteractiveWindow_InProc _interactiveWindowInProc;
internal InteractiveWindow_OutOfProc(VisualStudioInstance visualStudioInstance)
: base (visualStudioInstance)
{
_inProc = CreateInProcComponent(visualStudioInstance);
_interactiveWindowInProc = (InteractiveWindow_InProc)_textViewWindowInProc;
}
internal abstract InteractiveWindow_InProc CreateInProcComponent(VisualStudioInstance visualStudioInstance);
public void Initialize()
=> _inProc.Initialize();
=> _interactiveWindowInProc.Initialize();
/// <summary>
/// Gets the last output from the REPL.
/// </summary>
public string GetLastReplOutput()
=> _inProc.GetLastReplOutput();
=> _interactiveWindowInProc.GetLastReplOutput();
/// <summary>
/// Gets the last input from the REPL.
/// </summary>
public string GetLastReplInput()
=> _inProc.GetLastReplInput();
public int GetCaretPosition()
=> _inProc.GetCaretPosition();
=> _interactiveWindowInProc.GetLastReplInput();
public string GetReplText()
=> _inProc.GetReplText();
=> _interactiveWindowInProc.GetReplText();
/// <summary>
/// Gets the contents of the REPL window without the prompt text.
/// </summary>
public string GetReplTextWithoutPrompt()
=> _inProc.GetReplTextWithoutPrompt();
=> _interactiveWindowInProc.GetReplTextWithoutPrompt();
public void ShowWindow(bool waitForPrompt = true)
=> _inProc.ShowWindow(waitForPrompt);
=> _interactiveWindowInProc.ShowWindow(waitForPrompt);
public void Reset(bool waitForPrompt = true)
=> _inProc.Reset(waitForPrompt);
=> _interactiveWindowInProc.Reset(waitForPrompt);
public void SubmitText(string text, bool waitForPrompt = true)
=> _inProc.SubmitText(text, waitForPrompt);
=> _interactiveWindowInProc.SubmitText(text, waitForPrompt);
public void WaitForReplOutput(string outputText)
=> _inProc.WaitForReplOutput(outputText);
=> _interactiveWindowInProc.WaitForReplOutput(outputText);
public void WaitForReplOutputContains(string outputText)
=> _inProc.WaitForReplOutputContains(outputText);
=> _interactiveWindowInProc.WaitForReplOutputContains(outputText);
public void CloseInteractiveWindow()
=> _inProc.CloseWindow();
=> _interactiveWindowInProc.CloseWindow();
public void ClearScreen()
=> _inProc.ClearScreen();
=> _interactiveWindowInProc.ClearScreen();
public void InsertCode(string text)
=> _inProc.InsertCode(text);
=> _interactiveWindowInProc.InsertCode(text);
}
}
}
\ No newline at end of file
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.VisualStudio.IntegrationTest.Utilities.InProcess;
namespace Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess
{
public abstract class TextViewWindow_OutOfProc : OutOfProcComponent
{
internal readonly TextViewWindow_InProc _textViewWindowInProc;
internal TextViewWindow_OutOfProc(VisualStudioInstance visualStudioInstance)
: base(visualStudioInstance)
{
_textViewWindowInProc = CreateInProcComponent(visualStudioInstance);
}
internal abstract TextViewWindow_InProc CreateInProcComponent(VisualStudioInstance visualStudioInstance);
public int GetCaretPosition()
=> _textViewWindowInProc.GetCaretPosition();
public string[] GetCompletionItems()
{
WaitForCompletionSet();
return _textViewWindowInProc.GetCompletionItems();
}
public void PlaceCaret(
string marker,
int charsOffset,
int occurrence,
bool extendSelection,
bool selectBlock)
=> _textViewWindowInProc.PlaceCaret(
marker,
charsOffset,
occurrence,
extendSelection,
selectBlock);
public string[] GetCurrentClassifications()
=> _textViewWindowInProc.GetCurrentClassifications();
}
}
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
namespace Microsoft.VisualStudio.IntegrationTest.Utilities
{
/// <summary>
/// Provides methods for supporting temporary files within Roslyn tests.
/// </summary>
public class TemporaryTextFile : IDisposable
{
private string _fileName;
private string _content;
private string _path;
public TemporaryTextFile(string fileName, string content)
{
_fileName = fileName;
_content = content;
_path = IntegrationHelper.CreateTemporaryPath();
FullName = Path.Combine(_path, _fileName);
}
public void Create()
{
IntegrationHelper.CreateDirectory(_path, deleteExisting: true);
using (FileStream stream = File.Create(FullName))
{
}
File.WriteAllText(FullName, _content);
}
public string FullName { get; }
public void Dispose()
{
IntegrationHelper.DeleteDirectoryRecursively(_path);
}
}
}
......@@ -31,6 +31,7 @@
<Compile Include="Common\Signature.cs" />
<Compile Include="Helper.cs" />
<Compile Include="HostWaitHelper.cs" />
<Compile Include="InProcess\TextViewWindow_InProc.cs" />
<Compile Include="InProcess\CSharpInteractiveWindow_InProc.cs" />
<Compile Include="DialogHelpers.cs" />
<Compile Include="InProcess\FindReferencesWindow_InProc.cs" />
......@@ -54,7 +55,9 @@
<Compile Include="OutOfProcess\Shell_OutOfProc.cs" />
<Compile Include="OutOfProcess\SolutionExplorer_OutOfProc.cs" />
<Compile Include="InProcess\VisualStudioWorkspace_InProc.cs" />
<Compile Include="OutOfProcess\TextViewWindow_OutOfProc.cs" />
<Compile Include="ScreenshotService.cs" />
<Compile Include="TemporaryTextFile.cs" />
<Compile Include="TestUtilities.cs" />
<Compile Include="WellKnownCommandNames.cs" />
<Compile Include="VisualStudioInstance.cs" />
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册