|
' 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.
Imports System.Collections.Immutable
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.AddImport
Imports Microsoft.CodeAnalysis.Completion
Imports Microsoft.CodeAnalysis.CSharp.Formatting
Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.Formatting
Imports Microsoft.CodeAnalysis.Host.Mef
Imports Microsoft.CodeAnalysis.Options
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.VisualStudio.LanguageServices.CSharp.Snippets
Imports Microsoft.VisualStudio.Text.Editor
Imports Microsoft.VisualStudio.Text.Projection
Imports Roslyn.Test.Utilities
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.Snippets
<[UseExportProvider]>
<Trait(Traits.Feature, Traits.Features.Snippets)>
Public Class CSharpSnippetExpansionClientTests
<WpfFact>
Public Async Function TestAddImport_EmptyDocument() As Task
Dim originalCode = ""
Dim namespacesToAdd = {"System"}
Dim expectedUpdatedCode = "using System;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Async Function TestAddImport_EmptyDocument_SystemAtTop() As Task
Dim originalCode = ""
Dim namespacesToAdd = {"First.Alphabetically", "System.Bar"}
Dim expectedUpdatedCode = "using System.Bar;
using First.Alphabetically;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Async Function TestAddImport_EmptyDocument_SystemNotSortedToTop() As Task
Dim originalCode = ""
Dim namespacesToAdd = {"First.Alphabetically", "System.Bar"}
Dim expectedUpdatedCode = "using First.Alphabetically;
using System.Bar;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=False, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Async Function TestAddImport_AddsOnlyNewNamespaces() As Task
Dim originalCode = "using A.B.C;
using D.E.F;
"
Dim namespacesToAdd = {"D.E.F", "G.H.I"}
Dim expectedUpdatedCode = "using A.B.C;
using D.E.F;
using G.H.I;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WorkItem("https://github.com/dotnet/roslyn/issues/4457")>
<WpfFact>
Public Async Function TestAddImport_InsideNamespace() As Task
Dim originalCode = "
using A;
namespace N
{
using B;
class C
{
$$
}
}"
Dim namespacesToAdd = {"D"}
Dim expectedUpdatedCode = "
using A;
namespace N
{
using B;
using D;
class C
{
}
}"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Async Function TestAddImport_AddsOnlyNewAliasAndNamespacePairs() As Task
Dim originalCode = "using A = B.C;
using D = E.F;
using G = H.I;
"
Dim namespacesToAdd = {"A = E.F", "D = B.C", "G = H.I", "J = K.L"}
Dim expectedUpdatedCode = "using A = B.C;
using A = E.F;
using D = B.C;
using D = E.F;
using G = H.I;
using J = K.L;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Async Function TestAddImport_DuplicateNamespaceDetectionDoesNotIgnoreCase() As Task
Dim originalCode = "using A.b.C;
"
Dim namespacesToAdd = {"a.B.C", "A.B.c"}
Dim expectedUpdatedCode = "using a.B.C;
using A.b.C;
using A.B.c;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Async Function TestAddImport_DuplicateAliasNamespacePairDetectionIgnoresWhitespace1() As Task
Dim originalCode = "using A = B.C;
"
Dim namespacesToAdd = {"A = B.C"}
Dim expectedUpdatedCode = "using A = B.C;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Async Function TestAddImport_DuplicateAliasNamespacePairDetectionIgnoresWhitespace2() As Task
Dim originalCode = "using A = B.C;
"
Dim namespacesToAdd = {"A=B.C"}
Dim expectedUpdatedCode = "using A = B.C;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Async Function TestAddImport_DuplicateAliasNamespacePairDetectionDoesNotIgnoreCase() As Task
Dim originalCode = "using A = B.C;
"
Dim namespacesToAdd = {"a = b.C"}
Dim expectedUpdatedCode = "using a = b.C;
using A = B.C;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Async Function TestAddImport_OnlyFormatNewImports() As Task
Dim originalCode = "using A = B.C;
using G= H.I;
"
Dim namespacesToAdd = {"D =E.F"}
Dim expectedUpdatedCode = "using A = B.C;
using D = E.F;
using G= H.I;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/44423")>
Public Async Function TestAddImport_BadNamespaceGetsAdded() As Task
Dim originalCode = ""
Dim namespacesToAdd = {"$system"}
Dim expectedUpdatedCode = "using $system;
"
Await TestSnippetAddImportsAsync(originalCode, namespacesToAdd, placeSystemNamespaceFirst:=True, expectedUpdatedCode:=expectedUpdatedCode)
End Function
<WpfFact>
Public Sub TestSnippetFormatting_ProjectionBuffer_FullyInSubjectBuffer()
Dim workspaceXmlWithSubjectBufferDocument =
<Workspace>
<Project Language=<%= LanguageNames.CSharp %> CommonReferences="true">
<Document>class C {
void M()
{
{|S1:for (int x = 0; x < length; x++)
{
$$
}|}
}</Document>
</Project>
</Workspace>
Dim surfaceBufferDocument = <Document><div>
@[|{|S1:|} |]
</div></Document>
Dim expectedSurfaceBuffer = <SurfaceBuffer><div>
@for (int x = 0; x < length; x++)
{
}
</div></SurfaceBuffer>
TestProjectionFormatting(workspaceXmlWithSubjectBufferDocument, surfaceBufferDocument, expectedSurfaceBuffer)
End Sub
<WpfFact>
Public Sub TestSnippetFormatting_ProjectionBuffer_ExpandedIntoSurfaceBuffer()
Dim workspaceXmlWithSubjectBufferDocument =
<Workspace>
<Project Language=<%= LanguageNames.CSharp %> CommonReferences="true">
<Document>class C {
void M()
{
{|S1:for|}
}</Document>
</Project>
</Workspace>
Dim surfaceBufferDocument = <Document><div>
@[|{|S1:|} (int x = 0; x < length; x++)
{
$$
}|]
</div></Document>
Dim expectedSurfaceBuffer = <SurfaceBuffer><div>
@for (int x = 0; x < length; x++)
{
}
</div></SurfaceBuffer>
TestProjectionFormatting(workspaceXmlWithSubjectBufferDocument, surfaceBufferDocument, expectedSurfaceBuffer)
End Sub
<WpfFact>
Public Sub TestSnippetFormatting_ProjectionBuffer_FullyInSurfaceBuffer()
Dim workspaceXmlWithSubjectBufferDocument =
<Workspace>
<Project Language=<%= LanguageNames.CSharp %> CommonReferences="true">
<Document>class C {
void M()
{
{|S1:|}
}</Document>
</Project>
</Workspace>
Dim surfaceBufferDocument = <Document><div>
@[|{|S1:|}for (int x = 0; x < length; x++)
{
$$
}|]
</div></Document>
Dim expectedSurfaceBuffer = <SurfaceBuffer><div>
@for (int x = 0; x < length; x++)
{
}
</div></SurfaceBuffer>
TestProjectionFormatting(workspaceXmlWithSubjectBufferDocument, surfaceBufferDocument, expectedSurfaceBuffer)
End Sub
Public Sub TestSnippetFormatting_TabSize_3()
TestFormattingWithTabSize(3)
End Sub
<WpfTheory, WorkItem("https://github.com/dotnet/roslyn/issues/4652")>
<InlineData(3)>
<InlineData(4)>
<InlineData(5)>
Public Sub TestFormattingWithTabSize(tabSize As Integer)
Dim workspaceXml =
<Workspace>
<Project Language=<%= LanguageNames.CSharp %> CommonReferences="true">
<Document>class C {
void M()
{
[|for (int x = 0; x < length; x++)
{
$$
}|]
}
}</Document>
</Project>
</Workspace>
Dim expectedResult = <Test>class C {
void M()
{
for (int x = 0; x < length; x++)
{
}
}
}</Test>
Using workspace = TestWorkspace.Create(workspaceXml, openDocuments:=False)
Dim document = workspace.Documents.Single()
Dim textBuffer = document.GetTextBuffer()
Dim editorOptionsService = workspace.GetService(Of EditorOptionsService)()
Dim editorOptions = editorOptionsService.Factory.GetOptions(textBuffer)
editorOptions.SetOptionValue(DefaultOptions.ConvertTabsToSpacesOptionId, False)
editorOptions.SetOptionValue(DefaultOptions.TabSizeOptionId, tabSize)
editorOptions.SetOptionValue(DefaultOptions.IndentSizeOptionId, tabSize)
Dim snippetExpansionClient = New SnippetExpansionClient(
workspace.ExportProvider.GetExportedValue(Of IThreadingContext),
Guids.CSharpLanguageServiceId,
document.GetTextView(),
textBuffer,
signatureHelpControllerProvider:=Nothing,
editorCommandHandlerServiceFactory:=Nothing,
editorAdaptersFactoryService:=Nothing,
workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)().ToImmutableArray(),
editorOptionsService)
SnippetExpansionClientTestsHelper.TestFormattingAndCaretPosition(snippetExpansionClient, document, expectedResult, tabSize * 3)
End Using
End Sub
Public Sub TestProjectionFormatting(workspaceXmlWithSubjectBufferDocument As XElement, surfaceBufferDocumentXml As XElement, expectedSurfaceBuffer As XElement)
Using workspace = TestWorkspace.Create(workspaceXmlWithSubjectBufferDocument)
Dim subjectBufferDocument = workspace.Documents.Single()
Dim surfaceBufferDocument = workspace.CreateProjectionBufferDocument(
surfaceBufferDocumentXml.NormalizedValue,
{subjectBufferDocument},
options:=ProjectionBufferOptions.WritableLiteralSpans)
Dim snippetExpansionClient = New SnippetExpansionClient(
workspace.ExportProvider.GetExportedValue(Of IThreadingContext),
Guids.CSharpLanguageServiceId,
surfaceBufferDocument.GetTextView(),
subjectBufferDocument.GetTextBuffer(),
signatureHelpControllerProvider:=Nothing,
editorCommandHandlerServiceFactory:=Nothing,
editorAdaptersFactoryService:=Nothing,
workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)().ToImmutableArray(),
workspace.GetService(Of EditorOptionsService)())
SnippetExpansionClientTestsHelper.TestProjectionBuffer(snippetExpansionClient, surfaceBufferDocument, expectedSurfaceBuffer)
End Using
End Sub
Private Shared Async Function TestSnippetAddImportsAsync(
markupCode As String,
namespacesToAdd As String(),
placeSystemNamespaceFirst As Boolean,
expectedUpdatedCode As String) As Tasks.Task
Dim originalCode As String = Nothing
Dim position As Integer?
MarkupTestFile.GetPosition(markupCode, originalCode, position)
Dim workspaceXml = <Workspace>
<Project Language=<%= LanguageNames.CSharp %> CommonReferences="true">
<Document><%= originalCode %></Document>
</Project>
</Workspace>
Dim snippetNode = <Snippet>
<Imports>
</Imports>
</Snippet>
For Each namespaceToAdd In namespacesToAdd
snippetNode.Element("Imports").Add(<Import>
<Namespace><%= namespaceToAdd %></Namespace>
</Import>)
Next
Using workspace = TestWorkspace.CreateCSharp(originalCode)
Dim expansionClient = New SnippetExpansionClient(
workspace.ExportProvider.GetExportedValue(Of IThreadingContext),
Guids.VisualBasicDebuggerLanguageId,
workspace.Documents.Single().GetTextView(),
workspace.Documents.Single().GetTextBuffer(),
signatureHelpControllerProvider:=Nothing,
editorCommandHandlerServiceFactory:=Nothing,
editorAdaptersFactoryService:=Nothing,
workspace.ExportProvider.GetExports(Of ArgumentProvider, OrderableLanguageMetadata)().ToImmutableArray(),
workspace.GetService(Of EditorOptionsService)())
Dim document = workspace.CurrentSolution.Projects.Single().Documents.Single()
Dim addImportOptions = New AddImportPlacementOptions() With
{
.PlaceSystemNamespaceFirst = placeSystemNamespaceFirst
}
Dim formattingOptions = CSharpSyntaxFormattingOptions.Default
Dim updatedDocument = expansionClient.AddImports(
document,
addImportOptions,
formattingOptions,
If(position, 0),
snippetNode,
CancellationToken.None)
Assert.Equal(expectedUpdatedCode,
(Await updatedDocument.GetTextAsync()).ToString())
End Using
End Function
End Class
End Namespace
|