File: ChangeSignature\ChangeSignatureViewModelTests.vb
Web Access
Project: src\src\VisualStudio\Core\Test\Microsoft.VisualStudio.LanguageServices.UnitTests.vbproj (Microsoft.VisualStudio.LanguageServices.UnitTests)
' 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.ChangeSignature
Imports Microsoft.CodeAnalysis.Editor.Shared.Utilities
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Extensions
Imports Microsoft.CodeAnalysis.Editor.UnitTests.Workspaces
Imports Microsoft.CodeAnalysis.LanguageService
Imports Microsoft.CodeAnalysis.Shared.Extensions
Imports Microsoft.CodeAnalysis.Test.Utilities
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature
Imports Microsoft.VisualStudio.LanguageServices.Implementation.ChangeSignature.ChangeSignatureDialogViewModel
Imports Microsoft.VisualStudio.Text.Classification
Imports Roslyn.Test.Utilities
Imports Roslyn.Utilities
 
Namespace Microsoft.VisualStudio.LanguageServices.UnitTests.ChangeSignature
    <[UseExportProvider]>
    <Trait(Traits.Feature, Traits.Features.ChangeSignature)>
    Public Class ChangeSignatureViewModelTests
 
        <Fact>
        Public Async Function ReorderParameters_MethodWithTwoNormalParameters_UpDownArrowsNotOfferedWhenNoSelection() As Tasks.Task
            Dim markup = <Text><![CDATA[
class MyClass
{
    public void $$M(int x, string y)
    {
    }
}"]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "public void M(int x, string y)")
 
            Dim monitor = New PropertyChangedTestMonitor(viewModel)
            monitor.AddExpectation(Function() viewModel.CanMoveDown)
 
            viewModel.SelectedIndex = -1
 
            VerifyAlteredState(
                viewModelTestState,
                monitor,
                canCommit:=False,
                canMoveUp:=False,
                canMoveDown:=False)
 
            monitor.Detach()
        End Function
 
        <Fact>
        Public Async Function ReorderParameters_MethodWithTwoNormalParameters_CannotCommitAfterPermutationsResultingInOriginalOrdering() As Tasks.Task
            Dim markup = <Text><![CDATA[
class MyClass
{
    public void $$M(int x, string y)
    {
    }
}"]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "public void M(int x, string y)")
 
            viewModel.MoveDown()
            Assert.True(viewModel.TrySubmit)
 
            viewModel.MoveUp()
            Dim message As String = Nothing
            Assert.False(viewModel.CanSubmit(message))
            Assert.Equal(ServicesVSResources.You_must_change_the_signature, message)
 
            VerifyAlteredState(
                viewModelTestState,
                canCommit:=False,
                canMoveUp:=False,
                canMoveDown:=True)
        End Function
 
        <Fact>
        Public Async Function ReorderParameters_MethodWithTwoNormalParameters_MoveFirstParameterDown() As Tasks.Task
            Dim markup = <Text><![CDATA[
class MyClass
{
    public void $$M(int x, string y)
    {
    }
}"]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "public void M(int x, string y)")
 
            Dim monitor = New PropertyChangedTestMonitor(viewModel)
            monitor.AddExpectation(Function() viewModel.SignatureDisplay)
            monitor.AddExpectation(Function() viewModel.SignaturePreviewAutomationText)
            monitor.AddExpectation(Function() viewModel.AllParameters)
            monitor.AddExpectation(Function() viewModel.CanMoveUp)
            monitor.AddExpectation(Function() viewModel.MoveUpAutomationText)
            monitor.AddExpectation(Function() viewModel.CanMoveDown)
            monitor.AddExpectation(Function() viewModel.MoveDownAutomationText)
 
            viewModel.MoveDown()
 
            VerifyAlteredState(
                viewModelTestState,
                monitor,
                canCommit:=True,
                canMoveUp:=True,
                canMoveDown:=False,
                permutation:={1, 0},
                signatureDisplay:="public void M(string y, int x)")
 
            monitor.Detach()
        End Function
 
        <Fact>
        Public Async Function ReorderParameters_MethodWithTwoNormalParameters_RemoveFirstParameter() As Tasks.Task
            Dim markup = <Text><![CDATA[
class MyClass
{
    public void $$M(int x, string y)
    {
    }
}"]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "public void M(int x, string y)")
 
            Dim monitor = New PropertyChangedTestMonitor(viewModel)
            monitor.AddExpectation(Function() viewModel.SignatureDisplay)
            monitor.AddExpectation(Function() viewModel.SignaturePreviewAutomationText)
            monitor.AddExpectation(Function() viewModel.AllParameters)
            monitor.AddExpectation(Function() viewModel.CanRemove)
            monitor.AddExpectation(Function() viewModel.RemoveAutomationText)
            monitor.AddExpectation(Function() viewModel.CanRestore)
            monitor.AddExpectation(Function() viewModel.RestoreAutomationText)
 
            viewModel.Remove()
 
            VerifyAlteredState(
                viewModelTestState,
                monitor,
                canCommit:=True,
                canMoveUp:=False,
                canMoveDown:=True,
                permutation:={1},
                signatureDisplay:="public void M(string y)")
 
            monitor.Detach()
        End Function
 
        <Fact>
        Public Async Function ReorderParameters_MethodWithTwoNormalParameters_MoveSecondParameterUp() As Tasks.Task
            Dim markup = <Text><![CDATA[
class MyClass
{
    public void $$M(int x, string y)
    {
    }
}"]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "public void M(int x, string y)")
 
            Dim selectionChangedMonitor = New PropertyChangedTestMonitor(viewModel, strict:=True)
            selectionChangedMonitor.AddExpectation(Function() viewModel.CanMoveUp)
            selectionChangedMonitor.AddExpectation(Function() viewModel.MoveUpAutomationText)
            selectionChangedMonitor.AddExpectation(Function() viewModel.CanMoveDown)
            selectionChangedMonitor.AddExpectation(Function() viewModel.MoveDownAutomationText)
            selectionChangedMonitor.AddExpectation(Function() viewModel.CanRemove)
            selectionChangedMonitor.AddExpectation(Function() viewModel.RemoveAutomationText)
            selectionChangedMonitor.AddExpectation(Function() viewModel.CanRestore)
            selectionChangedMonitor.AddExpectation(Function() viewModel.RestoreAutomationText)
 
            viewModel.SelectedIndex = 1
 
            selectionChangedMonitor.VerifyExpectations()
            selectionChangedMonitor.Detach()
 
            VerifyAlteredState(
                viewModelTestState,
                canMoveUp:=True,
                canMoveDown:=False)
 
            Dim monitor = New PropertyChangedTestMonitor(viewModel)
            monitor.AddExpectation(Function() viewModel.SignatureDisplay)
            monitor.AddExpectation(Function() viewModel.SignaturePreviewAutomationText)
            monitor.AddExpectation(Function() viewModel.AllParameters)
            monitor.AddExpectation(Function() viewModel.CanMoveUp)
            monitor.AddExpectation(Function() viewModel.MoveUpAutomationText)
            monitor.AddExpectation(Function() viewModel.CanMoveDown)
            monitor.AddExpectation(Function() viewModel.MoveDownAutomationText)
 
            viewModel.MoveUp()
 
            VerifyAlteredState(
                viewModelTestState,
                monitor,
                canCommit:=True,
                canMoveUp:=False,
                canMoveDown:=True,
                permutation:={1, 0},
                signatureDisplay:="public void M(string y, int x)")
 
            monitor.VerifyExpectations()
            monitor.Detach()
        End Function
 
        <Fact>
        Public Async Function ChangeSignature_ParameterDisplay_MultidimensionalArray() As Tasks.Task
            Dim markup = <Text><![CDATA[
class MyClass
{
    public void $$M(int[,] x)
    {
    }
}"]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "public void M(int[,] x)")
            VerifyParameterInfo(
                viewModel,
                parameterIndex:=0,
                type:="int[,]")
        End Function
 
        <Fact, WorkItem("https://github.com/dotnet/roslyn/issues/8437")>
        Public Async Function ChangeSignature_ParameterDisplay_RefReturns() As Tasks.Task
            Dim markup = <Text><![CDATA[
class MyClass
{
    public ref int $$M(int[,] x)
    {
    }
}"]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "public ref int M(int[,] x)")
            VerifyParameterInfo(
                viewModel,
                parameterIndex:=0,
                type:="int[,]")
        End Function
 
        <Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30315")>
        Public Async Function ChangeSignature_ParameterDisplay_Nullable() As Tasks.Task
            Dim markup = <Text><![CDATA[
#nullable enable
class MyClass
{
    public string? $$M(string? x)
    {
    }
}"]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "public string? M(string? x)")
            VerifyParameterInfo(
                viewModel,
                parameterIndex:=0,
                type:="string?")
        End Function
 
        <WorkItem("https://github.com/dotnet/roslyn/issues/8437")>
        Public Async Function ChangeSignature_VerifyParamsArrayFunctionality() As Tasks.Task
            Dim markup = <Text><![CDATA[
class MyClass
{
    public ref int $$M(int x, params int[] y)
      {
    }
}"]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "public ref int M(int x, params int[] y)")
 
            viewModel.SelectedIndex = 1
 
            VerifyAlteredState(viewModelTestState,
                canMoveUp:=False,
                canMoveDown:=False,
                canRemove:=True)
        End Function
 
        <Fact>
        Public Async Function TestRefKindsDisplayedCorrectly() As Tasks.Task
            Dim includedInTest = {RefKind.None, RefKind.Ref, RefKind.Out, RefKind.In, RefKind.RefReadOnly, RefKind.RefReadOnlyParameter}
            Assert.Equal(includedInTest, EnumUtilities.GetValues(Of RefKind)())
 
            Dim markup = <Text><![CDATA[
class Test
{
    private void Method$$(int p1, ref int p2, in int p3, out int p4, ref readonly int p5) { }
}"]]></Text>
 
            Dim state = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            VerifyOpeningState(state.ViewModel, "private void Method(int p1, ref int p2, in int p3, out int p4, ref readonly int p5)")
 
            Assert.Equal("", state.ViewModel.AllParameters(0).Modifier)
            Assert.Equal("ref", state.ViewModel.AllParameters(1).Modifier)
            Assert.Equal("in", state.ViewModel.AllParameters(2).Modifier)
            Assert.Equal("out", state.ViewModel.AllParameters(3).Modifier)
            Assert.Equal("ref readonly", state.ViewModel.AllParameters(4).Modifier)
        End Function
 
        <Fact, WorkItem("https://github.com/dotnet/roslyn/issues/30315")>
        Public Async Function ChangeSignature_ParameterDisplay_DefaultStruct() As Tasks.Task
            Dim markup = <Text><![CDATA[
struct MyStruct
{

}

class Goo
{
    void $$Bar(MyStruct s = default(MyStruct))
    {

    }
}]]></Text>
 
            Dim viewModelTestState = Await GetViewModelTestStateAsync(markup, LanguageNames.CSharp)
            Dim viewModel = viewModelTestState.ViewModel
            VerifyOpeningState(viewModel, "private void Bar(MyStruct s = default(MyStruct))")
            VerifyParameterInfo(
                viewModel,
                parameterIndex:=0,
                type:="MyStruct",
                defaultValue:="default")
        End Function
 
        Private Shared Sub VerifyAlteredState(
           viewModelTestState As ChangeSignatureViewModelTestState,
           Optional monitor As PropertyChangedTestMonitor = Nothing,
           Optional canCommit As Boolean? = Nothing,
           Optional canMoveUp As Boolean? = Nothing,
           Optional canMoveDown As Boolean? = Nothing,
           Optional canRemove As Boolean? = Nothing,
           Optional canRestore As Boolean? = Nothing,
           Optional permutation As Integer() = Nothing,
           Optional signatureDisplay As String = Nothing)
 
            Dim viewModel = viewModelTestState.ViewModel
 
            If monitor IsNot Nothing Then
                monitor.VerifyExpectations()
            End If
 
            If canCommit IsNot Nothing Then
                Dim message As String = Nothing
                Assert.Equal(canCommit, viewModel.CanSubmit(message))
 
                If canCommit.Value Then
                    Assert.True(viewModel.TrySubmit())
                End If
            End If
 
            If canMoveUp IsNot Nothing Then
                Assert.Equal(canMoveUp, viewModel.CanMoveUp)
            End If
 
            If canMoveDown IsNot Nothing Then
                Assert.Equal(canMoveDown, viewModel.CanMoveDown)
            End If
 
            If canRemove IsNot Nothing Then
                Assert.Equal(canRemove, viewModel.CanRemove)
            End If
 
            If canRestore IsNot Nothing Then
                Assert.Equal(canRestore, viewModel.CanRestore)
            End If
 
            If permutation IsNot Nothing Then
                AssertPermuted(permutation, viewModel.AllParameters, viewModelTestState.OriginalParameterList)
            End If
 
            If signatureDisplay IsNot Nothing Then
                Assert.Equal(signatureDisplay, viewModel.TEST_GetSignatureDisplayText())
            End If
 
        End Sub
 
        Private Shared Sub AssertPermuted(permutation As Integer(), actualParameterList As List(Of ChangeSignatureDialogViewModel.ParameterViewModel), originalParameterList As ImmutableArray(Of IParameterSymbol))
            Dim finalParameterList = actualParameterList.Where(Function(p) Not p.IsRemoved)
            For index = 0 To permutation.Length - 1
                Dim expected = originalParameterList(permutation(index))
                Assert.Equal(expected, DirectCast(finalParameterList(index), ExistingParameterViewModel).ParameterSymbol)
            Next
        End Sub
 
        Private Shared Sub VerifyOpeningState(viewModel As ChangeSignatureDialogViewModel, openingSignatureDisplay As String)
            Assert.Equal(openingSignatureDisplay, viewModel.TEST_GetSignatureDisplayText())
            Dim message As String = Nothing
            Assert.False(viewModel.CanSubmit(message))
            Assert.Equal(ServicesVSResources.You_must_change_the_signature, message)
            Assert.False(viewModel.CanMoveUp)
        End Sub
 
        Private Shared Sub VerifyParameterInfo(
            viewModel As ChangeSignatureDialogViewModel,
                parameterIndex As Integer,
                Optional modifier As String = Nothing,
                Optional type As String = Nothing,
                Optional parameterName As String = Nothing,
                Optional defaultValue As String = Nothing,
                Optional isDisabled As Boolean? = Nothing,
                Optional isRemoved As Boolean? = Nothing)
 
            Dim parameter = viewModel.AllParameters(parameterIndex)
 
            If modifier IsNot Nothing Then
                Assert.Equal(modifier, parameter.Modifier)
            End If
 
            If type IsNot Nothing Then
                Assert.Equal(type, parameter.Type)
            End If
 
            If parameterName IsNot Nothing Then
                Assert.Equal(parameterName, parameter.ParameterName)
            End If
 
            If defaultValue IsNot Nothing Then
                Assert.Equal(defaultValue, parameter.Default)
            End If
 
            If isDisabled.HasValue Then
                Assert.Equal(isDisabled.Value, parameter.IsDisabled)
            End If
 
            If isRemoved.HasValue Then
                Assert.Equal(isRemoved.Value, parameter.IsRemoved)
            End If
        End Sub
 
        Private Shared Async Function GetViewModelTestStateAsync(
            markup As XElement,
            languageName As String) As Tasks.Task(Of ChangeSignatureViewModelTestState)
 
            Dim workspaceXml =
            <Workspace>
                <Project Language=<%= languageName %> CommonReferences="true">
                    <Document><%= markup.NormalizedValue.Replace(vbCrLf, vbLf) %></Document>
                </Project>
            </Workspace>
 
            Using workspace = EditorTestWorkspace.Create(workspaceXml)
                Dim doc = workspace.Documents.Single()
                Dim workspaceDoc = workspace.CurrentSolution.GetDocument(doc.Id)
                If (Not doc.CursorPosition.HasValue) Then
                    Assert.True(False, "Missing caret location in document.")
                End If
 
                Dim tree = Await workspaceDoc.GetSyntaxTreeAsync()
                Dim token = Await tree.GetTouchingWordAsync(doc.CursorPosition.Value, workspaceDoc.Project.Services.GetService(Of ISyntaxFactsService)(), CancellationToken.None)
                Dim symbol = (Await workspaceDoc.GetSemanticModelAsync()).GetDeclaredSymbol(token.Parent)
 
                Dim document = Await SemanticDocument.CreateAsync(workspaceDoc, CancellationToken.None)
                Dim viewModel = New ChangeSignatureDialogViewModel(
                    document,
                    ParameterConfiguration.Create(symbol.GetParameters().Select(Function(p) DirectCast(New ExistingParameter(p), Parameter)).ToImmutableArray(), symbol.IsExtensionMethod(), selectedIndex:=0),
                    symbol,
                    positionForTypeBinding:=0,
                    workspace.ExportProvider.GetExportedValue(Of IClassificationFormatMapService)().GetClassificationFormatMap("text"),
                    workspace.ExportProvider.GetExportedValue(Of ClassificationTypeMap)())
                Return New ChangeSignatureViewModelTestState(viewModel, symbol.GetParameters())
            End Using
        End Function
    End Class
End Namespace