-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extending the supported functionality of the VisualStudio IntegrationTest Utilities and adding the start of 'CSharpAutomaticBraceCompletion' #11223
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,6 +62,7 @@ | |
<InternalsVisibleToTest Include="Roslyn.Services.UnitTests" /> | ||
<InternalsVisibleToTest Include="Roslyn.VisualStudio.DiagnosticsWindow" /> | ||
<InternalsVisibleToTest Include="Roslyn.VisualStudio.Services.UnitTests" /> | ||
<InternalsVisibleToTest Include="Roslyn.VisualStudio.Test.Utilities" /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IAsynchronousOperationWaiter is unavailable otherwise. |
||
<InternalsVisibleToTest Include="RoslynETAHost" /> | ||
<InternalsVisibleToTest Include="RoslynTaoActions" /> | ||
<InternalsVisibleToTest Include="Roslyn.VisualStudio.CSharp.UnitTests" /> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
// 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.Threading.Tasks; | ||
using Roslyn.Test.Utilities; | ||
using Roslyn.VisualStudio.IntegrationTests; | ||
using Roslyn.VisualStudio.Test.Utilities; | ||
using Xunit; | ||
|
||
namespace Roslyn.VisualStudio.CSharp.IntegrationTests | ||
{ | ||
[Collection(nameof(SharedIntegrationHostFixture))] | ||
public class CSharpAutomaticBraceCompletion : IDisposable | ||
{ | ||
private readonly VisualStudioInstanceContext _visualStudio; | ||
private readonly Workspace _workspace; | ||
private readonly Solution _solution; | ||
private readonly Project _project; | ||
private readonly EditorWindow _editorWindow; | ||
|
||
public CSharpAutomaticBraceCompletion(VisualStudioInstanceFactory instanceFactory) | ||
{ | ||
_visualStudio = instanceFactory.GetNewOrUsedInstance(); | ||
|
||
_solution = _visualStudio.Instance.SolutionExplorer.CreateSolution(nameof(CSharpAutomaticBraceCompletion)); | ||
_project = _solution.AddProject("TestProj", ProjectTemplate.ClassLibrary, ProjectLanguage.CSharp); | ||
|
||
_workspace = _visualStudio.Instance.Workspace; | ||
_workspace.UseSuggestionMode = false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this necessary for the test? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ported from the existing test, someone with more context would need to say whether it is actually still required. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please delete and see if it's still needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It appears to still be needed for some test which I haven't ported yet (tested by modifying the existing action locally and running the full CSharpAutomaticBraceCompletion test) |
||
|
||
_editorWindow = _visualStudio.Instance.EditorWindow; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
_visualStudio.Dispose(); | ||
} | ||
|
||
[Fact] | ||
public async Task BracesInsertionAndTabCompleting() | ||
{ | ||
_editorWindow.Text = @"class C { | ||
void Foo() { | ||
// Marker | ||
} | ||
}"; | ||
|
||
_editorWindow.PlaceCursor("// Marker"); | ||
|
||
await _editorWindow.TypeTextAsync("if (true) {"); | ||
|
||
Assert.Equal(" if (true) { ", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal("}", _editorWindow.CurrentLineTextAfterCursor); | ||
|
||
await _editorWindow.TypeTextAsync($"{EditorWindow.TAB}"); | ||
|
||
Assert.Equal(" if (true) { }", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor); | ||
} | ||
|
||
[Fact] | ||
public async Task BracesOvertyping() | ||
{ | ||
_editorWindow.Text = @"class C { | ||
void Foo() { | ||
// Marker | ||
} | ||
}"; | ||
|
||
_editorWindow.PlaceCursor("// Marker"); | ||
|
||
await _editorWindow.TypeTextAsync("if (true) {"); | ||
await _editorWindow.TypeTextAsync("}"); | ||
|
||
Assert.Equal(" if (true) { }", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor); | ||
} | ||
|
||
[Fact] | ||
public async Task BracesOnReturnNoFormattingOnlyIndentationBeforeCloseBrace() | ||
{ | ||
_editorWindow.Text = @"class C { | ||
void Foo() { | ||
// Marker | ||
} | ||
}"; | ||
|
||
_editorWindow.PlaceCursor("// Marker"); | ||
|
||
await _editorWindow.TypeTextAsync("if (true) {"); | ||
await _editorWindow.TypeTextAsync($"{EditorWindow.ENTER}"); | ||
await _editorWindow.TypeTextAsync("var a = 1;"); | ||
|
||
Assert.Equal(" var a = 1;", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor); | ||
} | ||
|
||
[Fact] | ||
public async Task BracesOnReturnOvertypingTheClosingBrace() | ||
{ | ||
_editorWindow.Text = @"class C { | ||
void Foo() { | ||
// Marker | ||
} | ||
}"; | ||
|
||
_editorWindow.PlaceCursor("// Marker"); | ||
|
||
await _editorWindow.TypeTextAsync("if (true) {"); | ||
await _editorWindow.TypeTextAsync($"{EditorWindow.ENTER}"); | ||
await _editorWindow.TypeTextAsync("var a = 1;}"); | ||
|
||
Assert.Equal(" }", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor); | ||
|
||
Assert.Contains(@"if (true) | ||
{ | ||
var a = 1; | ||
} | ||
", _editorWindow.Text); | ||
} | ||
|
||
[Fact] | ||
[WorkItem(653540, "DevDiv")] | ||
public async Task BracesOnReturnWithNonWhitespaceSpanInside() | ||
{ | ||
_editorWindow.Text = string.Empty; | ||
|
||
await _editorWindow.TypeTextAsync("class A { int i;"); | ||
await _editorWindow.TypeTextAsync($"{EditorWindow.ENTER}"); | ||
|
||
Assert.Equal(string.Empty, _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal("}", _editorWindow.CurrentLineTextAfterCursor); | ||
|
||
Assert.Contains(@"class A { int i; | ||
}", _editorWindow.Text); | ||
} | ||
|
||
[Fact] | ||
public async Task ParenInsertionAndTabCompleting() | ||
{ | ||
_editorWindow.Text = @"class C { | ||
//Marker | ||
}"; | ||
|
||
_editorWindow.PlaceCursor("// Marker"); | ||
|
||
await _editorWindow.TypeTextAsync("void Foo("); | ||
|
||
Assert.Equal(" void Foo(", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal(")", _editorWindow.CurrentLineTextAfterCursor); | ||
|
||
await _editorWindow.TypeTextAsync("int x"); | ||
await _editorWindow.TypeTextAsync($"{EditorWindow.TAB}"); | ||
|
||
Assert.Equal(" void Foo(int x)", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor); | ||
} | ||
|
||
[Fact] | ||
public async Task ParenOvertyping() | ||
{ | ||
_editorWindow.Text = @"class C { | ||
//Marker | ||
}"; | ||
|
||
_editorWindow.PlaceCursor("// Marker"); | ||
|
||
await _editorWindow.TypeTextAsync("void Foo("); | ||
await _editorWindow.TypeTextAsync($"{EditorWindow.ESC}"); | ||
await _editorWindow.TypeTextAsync(")"); | ||
|
||
Assert.Equal(" void Foo()", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal(")", _editorWindow.CurrentLineTextAfterCursor); | ||
} | ||
|
||
[Fact] | ||
public async Task SquareBracketInsertion() | ||
{ | ||
_editorWindow.Text = @"class C { | ||
//Marker | ||
}"; | ||
|
||
_editorWindow.PlaceCursor("// Marker"); | ||
|
||
await _editorWindow.TypeTextAsync("int ["); | ||
|
||
Assert.Equal(" int [", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal("]", _editorWindow.CurrentLineTextAfterCursor); | ||
} | ||
|
||
[Fact] | ||
public async Task SquareBracketOvertyping() | ||
{ | ||
_editorWindow.Text = @"class C { | ||
//Marker | ||
}"; | ||
|
||
_editorWindow.PlaceCursor("// Marker"); | ||
|
||
await _editorWindow.TypeTextAsync("int ["); | ||
await _editorWindow.TypeTextAsync("]"); | ||
|
||
Assert.Equal(" int []", _editorWindow.CurrentLineTextBeforeCursor); | ||
Assert.Equal(string.Empty, _editorWindow.CurrentLineTextAfterCursor); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// 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.Threading.Tasks; | ||
using EnvDTE; | ||
|
||
namespace Roslyn.VisualStudio.Test.Utilities | ||
{ | ||
public static class DteExtensions | ||
{ | ||
public static async Task ExecuteCommandAsync(this DTE dte, string command, string args = "") | ||
{ | ||
// args is "" the default because it is the default value used by Dte.ExecuteCommand and changing our default | ||
// to something more logical, like null, would change the expected behavior of Dte.ExecuteCommand | ||
|
||
await dte.WaitForCommandAvailabilityAsync(command).ConfigureAwait(continueOnCapturedContext: false); | ||
IntegrationHelper.RetryRpcCall(() => dte.ExecuteCommand(command, args)); | ||
} | ||
|
||
public static Window LocateWindow(this DTE dte, string windowTitle) | ||
{ | ||
var dteWindows = IntegrationHelper.RetryRpcCall(() => dte.Windows); | ||
|
||
foreach (Window window in dteWindows) | ||
{ | ||
var windowCaption = IntegrationHelper.RetryRpcCall(() => window.Caption); | ||
|
||
if (windowCaption.Equals(windowTitle)) | ||
{ | ||
return window; | ||
} | ||
} | ||
return null; | ||
} | ||
|
||
public static Task WaitForCommandAvailabilityAsync(this DTE dte, string command) | ||
=> IntegrationHelper.WaitForResultAsync(() => IntegrationHelper.RetryRpcCall(() => dte.Commands.Item(command).IsAvailable), expectedResult: true); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// 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.Reflection; | ||
|
||
namespace Roslyn.VisualStudio.Test.Utilities | ||
{ | ||
internal static class IntegrationServiceExtensions | ||
{ | ||
public static void Execute(this IntegrationService integrationService, Type type, string methodName, BindingFlags bindingFlags = (BindingFlags.Public | BindingFlags.Static), params object[] parameters) | ||
=> Execute(integrationService, type.Assembly.Location, type.FullName, methodName, bindingFlags, parameters); | ||
|
||
public static T Execute<T>(this IntegrationService integrationService, Type type, string methodName, BindingFlags bindingFlags = (BindingFlags.Public | BindingFlags.Static), params object[] parameters) | ||
=> Execute<T>(integrationService, type.Assembly.Location, type.FullName, methodName, bindingFlags, parameters); | ||
|
||
public static void Execute(this IntegrationService integrationService, string assemblyFilePath, string typeFullName, string methodName, BindingFlags bindingFlags = (BindingFlags.Public | BindingFlags.Static), params object[] parameters) | ||
{ | ||
var result = integrationService.Execute(assemblyFilePath, typeFullName, methodName, bindingFlags, parameters); | ||
|
||
if (result != null) | ||
{ | ||
throw new InvalidOperationException("The specified call was not expected to return a value."); | ||
} | ||
} | ||
|
||
public static T Execute<T>(this IntegrationService integrationService, string assemblyFilePath, string typeFullName, string methodName, BindingFlags bindingFlags = (BindingFlags.Public | BindingFlags.Static), params object[] parameters) | ||
{ | ||
var objectUri = integrationService.Execute(assemblyFilePath, typeFullName, methodName, bindingFlags, parameters); | ||
|
||
if (objectUri == null) | ||
{ | ||
throw new InvalidOperationException("The specified call was expected to return a value."); | ||
} | ||
|
||
return (T)(Activator.GetObject(typeof(T), $"{integrationService.Uri}/{objectUri}")); | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why? This seems very fishy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EditorCompletionOptions.UseSuggestionMode is not available otherwise.