File: Interactive\Commands\InteractiveCommandHandlerTests.cs
Web Access
Project: src\src\VisualStudio\CSharp\Test\Microsoft.VisualStudio.LanguageServices.CSharp.UnitTests.csproj (Microsoft.VisualStudio.LanguageServices.CSharp.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.
 
#nullable disable
 
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Commanding;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Interactive.Commands;
 
[UseExportProvider]
[Trait(Traits.Feature, Traits.Features.Interactive)]
public sealed class InteractiveCommandHandlerTests
{
    private const string Caret = "$$";
    private const string ExampleCode1 = @"var x = 1;";
    private const string ExampleCode2 =
@"var x = 1;
Task.Run(() => { return 1; });";
    private const string ExampleCode2Line2 =
@"Task.Run(() => { return 1; });";
    private const string ExampleMultiline =
@"namespace N {
    void goo() {
        Console.WriteLine(
            $$""LLL"");
    }
}";
    private const string ExpectedMultilineSelection =
@"Console.WriteLine(
            ""LLL"");";
 
    [WpfFact]
    public void TestExecuteInInteractiveWithoutSelection()
    {
        AssertExecuteInInteractive(Caret, []);
 
        AssertExecuteInInteractive(
@"var x = 1;
$$
var y = 2;", []);
 
        AssertExecuteInInteractive(ExampleCode1 + Caret, ExampleCode1);
        AssertExecuteInInteractive(ExampleCode1.Insert(3, Caret), ExampleCode1);
        AssertExecuteInInteractive(ExampleCode2 + Caret, ExampleCode2Line2);
        AssertExecuteInInteractive(ExampleMultiline, ExpectedMultilineSelection);
    }
 
    [WpfFact]
    public void TestExecuteInInteractiveWithEmptyBuffer()
    {
        AssertExecuteInInteractive(
@"{|Selection:|}var x = 1;
{|Selection:$$|}var y = 2;", []);
 
        AssertExecuteInInteractive($@"{{|Selection:{ExampleCode1}$$|}}", ExampleCode1);
 
        AssertExecuteInInteractive($@"{{|Selection:{ExampleCode2}$$|}}", ExampleCode2);
 
        AssertExecuteInInteractive(
$@"var o = new object[] {{ 1, 2, 3 }};
Console.WriteLine(o);
{{|Selection:{ExampleCode2}$$|}}
 
Console.WriteLine(x);", ExampleCode2);
    }
 
    [WpfFact]
    public void TestExecuteInInteractiveWithBoxSelection()
    {
        var expectedBoxSubmissionResult = @"int x;
int y;";
        AssertExecuteInInteractive(
$@"some text {{|Selection:$$int x;|}} also here
text some {{|Selection:int y;|}} here also", expectedBoxSubmissionResult);
 
        AssertExecuteInInteractive(
$@"some text {{|Selection:int x;$$|}} also here
text some {{|Selection:int y;|}} here also", expectedBoxSubmissionResult);
 
        AssertExecuteInInteractive(
$@"some text {{|Selection:int x;|}} also here
text some {{|Selection:$$int y;|}} here also", expectedBoxSubmissionResult);
 
        AssertExecuteInInteractive(
$@"some text {{|Selection:int x;|}} also here
text some {{|Selection:int y;$$|}} here also", expectedBoxSubmissionResult);
    }
 
    [WpfFact]
    public void TestExecuteInInteractiveWithNonEmptyBuffer()
    {
        // Execute in interactive clears the existing current buffer before execution.
        // Therefore `var x = 1;` will not be executed.
        AssertExecuteInInteractive(
            @"{|Selection:var y = 2;$$|}",
            "var y = 2;",
            submissionBuffer: "var x = 1;");
    }
 
    [WpfFact(Skip = "https://github.com/dotnet/roslyn/issues/23200")]
    public void TestExecuteInInteractiveWithDefines()
    {
        var exampleWithIfDirective =
@"#if DEF
public void $$Run()
{
}
#endif";
 
        AssertExecuteInInteractive(exampleWithIfDirective,
@"public void Run()");
 
        var exampleWithDefine =
$@"#define DEF
{exampleWithIfDirective}";
 
        AssertExecuteInInteractive(exampleWithDefine,
@"public void Run()
{
}");
    }
 
    [WpfFact]
    public void TestCopyToInteractiveWithoutSelection()
    {
        AssertCopyToInteractive(Caret, "");
 
        AssertCopyToInteractive($"{ExampleCode2}$$", ExampleCode2Line2);
 
        AssertCopyToInteractive(
            code: ExampleCode2 + Caret,
            submissionBuffer: ExampleCode1,
            expectedBufferText: ExampleCode1 + "\r\n" + ExampleCode2Line2);
 
        AssertCopyToInteractive(
            code: ExampleCode2 + Caret,
            submissionBuffer: "x = 2;",
            expectedBufferText: "x = 2;\r\n" + ExampleCode2Line2);
    }
 
    [WpfFact]
    public void TestCopyToInteractive()
    {
        AssertCopyToInteractive($"{{|Selection:{ExampleCode2}$$|}}", ExampleCode2);
    }
 
    [WpfFact]
    public void TestCopyToInteractiveWithNonEmptyBuffer()
    {
        // Copy to interactive does not clear the existing buffer.
        // Therefore `var x = 1;` will still be present in the final buffer.
        AssertCopyToInteractive(
            $"{{|Selection:{ExampleCode2}$$|}}",
            $"var x = 1;\r\n{ExampleCode2}",
            submissionBuffer: "var x = 1;");
    }
 
    private static void AssertCopyToInteractive(string code, string expectedBufferText, string submissionBuffer = null)
    {
        using var workspace = InteractiveWindowCommandHandlerTestState.CreateTestState(code);
        PrepareSubmissionBuffer(submissionBuffer, workspace);
        workspace.SendCopyToInteractive();
        Assert.Equal(expectedBufferText, workspace.WindowCurrentLanguageBuffer.CurrentSnapshot.GetText());
    }
 
    private static void AssertExecuteInInteractive(string code, string expectedSubmission, string submissionBuffer = null)
    {
        AssertExecuteInInteractive(code, [expectedSubmission], submissionBuffer);
    }
 
    private static void AssertExecuteInInteractive(string code, string[] expectedSubmissions, string submissionBuffer = null)
    {
        var submissions = new List<string>();
        void appendSubmission(object _, string item)
        {
            submissions.Add(item.TrimEnd());
        }
 
        using var workspace = InteractiveWindowCommandHandlerTestState.CreateTestState(code);
        PrepareSubmissionBuffer(submissionBuffer, workspace);
        Assert.Equal(CommandState.Available, workspace.GetStateForExecuteInInteractive());
 
        workspace.Evaluator.OnExecute += appendSubmission;
        workspace.ExecuteInInteractive();
        AssertEx.Equal(expectedSubmissions, submissions);
    }
 
    private static void PrepareSubmissionBuffer(string submissionBuffer, InteractiveWindowCommandHandlerTestState workspace)
    {
        if (!string.IsNullOrEmpty(submissionBuffer))
        {
            workspace.WindowCurrentLanguageBuffer.Insert(0, submissionBuffer);
        }
    }
}