Skip to content
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

Merged
merged 3 commits into from
May 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/EditorFeatures/Core/EditorFeatures.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@
<InternalsVisibleToTest Include="Roslyn.Test.Utilities.Desktop" />
<InternalsVisibleToTest Include="Roslyn.VisualStudio.CSharp.UnitTests" />
<InternalsVisibleToTest Include="Roslyn.VisualStudio.Services.UnitTests" />
<InternalsVisibleToTest Include="Roslyn.VisualStudio.Test.Utilities" />
Copy link
Member

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.

Copy link
Member Author

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.

<!-- Eventually a bunch of these unit tests should move into Roslyn.Services.Implementation.UnitTests
and this should be removed. -->
<InternalsVisibleToTest Include="RoslynETAHost" />
Expand Down
1 change: 1 addition & 0 deletions src/Features/Core/Portable/Features.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Member Author

Choose a reason for hiding this comment

The 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" />
Expand Down
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;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this necessary for the test?

Copy link
Member Author

Choose a reason for hiding this comment

The 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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please delete and see if it's still needed.

Copy link
Member Author

Choose a reason for hiding this comment

The 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);
}
}
}
3 changes: 2 additions & 1 deletion src/VisualStudio/IntegrationTests/CSharp/CSharpBuild.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// 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 Roslyn.VisualStudio.IntegrationTests;
using Roslyn.VisualStudio.Test.Utilities;
using Xunit;

namespace Roslyn.VisualStudio.Integration.UnitTests
namespace Roslyn.VisualStudio.CSharp.IntegrationTests
{
[Collection(nameof(SharedIntegrationHostFixture))]
public class CSharpBuild : IDisposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

using System;
using System.Threading.Tasks;
using Roslyn.VisualStudio.IntegrationTests;
using Roslyn.VisualStudio.Test.Utilities;
using Xunit;

namespace Roslyn.VisualStudio.Integration.UnitTests
namespace Roslyn.VisualStudio.CSharp.IntegrationTests
{
[Collection(nameof(SharedIntegrationHostFixture))]
public class CSharpInteractiveDemo : IDisposable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Roslyn.VisualStudio.Test.Utilities;
using Xunit;

namespace Roslyn.VisualStudio.Integration.UnitTests
namespace Roslyn.VisualStudio.IntegrationTests
{
[CollectionDefinition(nameof(SharedIntegrationHostFixture))]
public sealed class SharedIntegrationHostFixture : ICollectionFixture<VisualStudioInstanceFactory>
Expand Down
3 changes: 2 additions & 1 deletion src/VisualStudio/IntegrationTests/VisualBasic/BasicBuild.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// 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 Roslyn.VisualStudio.IntegrationTests;
using Roslyn.VisualStudio.Test.Utilities;
using Xunit;

namespace Roslyn.VisualStudio.Integration.UnitTests
namespace Roslyn.VisualStudio.Basic.IntegrationTests
{
[Collection(nameof(SharedIntegrationHostFixture))]
public class BasicBuild
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<None Include="project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="CSharp\CSharpAutomaticBraceCompletion.cs" />
<Compile Include="CSharp\CSharpBuild.cs" />
<Compile Include="CSharp\CSharpInteractiveDemo.cs" />
<Compile Include="SharedIntegrationHostFixture.cs" />
Expand All @@ -31,6 +32,10 @@
<Project>{8635cb8f-d210-41ed-b4ff-71502cdb475c}</Project>
<Name>xUnit.net</Name>
</ProjectReference>
<ProjectReference Include="..\..\Test\Utilities\Desktop\TestUtilities.Desktop.csproj">
<Project>{76c6f005-c89d-4348-bb4a-391898dbeb52}</Project>
<Name>TestUtilities.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\TestUtilities\VisualStudioTestUtilities.csproj">
<Project>{3BED15FD-D608-4573-B432-1569C1026F6D}</Project>
<Name>VisualStudioTestUtilities</Name>
Expand Down
38 changes: 38 additions & 0 deletions src/VisualStudio/TestUtilities/Extensions/DteExtensions.cs
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}"));
}
}
}
Loading