File: RawStringLiteral\RawStringLiteralCommandHandlerTests.cs
Web Access
Project: src\src\EditorFeatures\CSharpTest\Microsoft.CodeAnalysis.CSharp.EditorFeatures.UnitTests.csproj (Microsoft.CodeAnalysis.CSharp.EditorFeatures.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.
 
using System.Linq;
using System.Xml.Linq;
using Microsoft.CodeAnalysis.Editor.CSharp.RawStringLiteral;
using Microsoft.CodeAnalysis.Editor.UnitTests;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Commanding;
using Roslyn.Test.Utilities;
using Xunit;
 
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.RawStringLiteral;
 
[UseExportProvider]
public class RawStringLiteralCommandHandlerTests
{
    internal sealed class RawStringLiteralTestState : AbstractCommandHandlerTestState
    {
        private static readonly TestComposition s_composition = EditorTestCompositions.EditorFeaturesWpf.AddParts(
            typeof(RawStringLiteralCommandHandler));
 
        private readonly RawStringLiteralCommandHandler _commandHandler;
 
        public RawStringLiteralTestState(XElement workspaceElement)
            : base(workspaceElement, s_composition)
        {
            _commandHandler = (RawStringLiteralCommandHandler)GetExportedValues<ICommandHandler>().
                Single(c => c is RawStringLiteralCommandHandler);
        }
 
        public static RawStringLiteralTestState CreateTestState(string markup, bool withSpansOnly = false)
            => new(GetWorkspaceXml(markup, withSpansOnly));
 
        public static XElement GetWorkspaceXml(string markup, bool withSpansOnly)
        {
            var spansOnlyMarkup = withSpansOnly ? """Markup="SpansOnly" """ : "";
            return XElement.Parse($"""
<Workspace>
    <Project Language="C#" CommonReferences="true">
        <Document {spansOnlyMarkup}>{markup}</Document>
    </Project>
</Workspace>
""");
        }
 
        internal void AssertCodeIs(string expectedCode, bool withSpansOnly = false)
        {
            if (withSpansOnly)
                expectedCode = expectedCode.Replace("$", "\uD7FF");
 
            MarkupTestFile.GetPositionAndSpans(expectedCode, out var massaged, out int? caretPosition, out var spans);
 
            if (withSpansOnly)
            {
                Assert.Null(caretPosition);
                massaged = massaged.Replace("\uD7FF", "$");
            }
 
            Assert.Equal(massaged, TextView.TextSnapshot.GetText());
 
            if (!withSpansOnly)
                Assert.Equal(caretPosition!.Value, TextView.Caret.Position.BufferPosition.Position);
 
            var virtualSpaces = spans.SingleOrDefault(kvp => kvp.Key.StartsWith("VirtualSpaces#"));
            if (virtualSpaces.Key != null)
            {
                var virtualOffset = int.Parse(virtualSpaces.Key["VirtualSpaces-".Length..]);
                Assert.True(TextView.Caret.InVirtualSpace);
                Assert.Equal(virtualOffset, TextView.Caret.Position.VirtualBufferPosition.VirtualSpaces);
            }
        }
 
        public void SendTypeChar(char ch)
            => SendTypeChar(ch, _commandHandler.ExecuteCommand, () => EditorOperations.InsertText(ch.ToString()));
 
        public void SendReturn(bool handled)
            => SendReturn(_commandHandler.ExecuteCommand, () =>
            {
                Assert.False(handled, "Return key should have been handled");
            });
    }
 
    #region enter tests
 
    [WpfFact]
    public void TestReturnInSixQuotes()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = """$$"""
            """");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = """
            $${|VirtualSpaces-4:|}
                """
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesWithSemicolonAfter()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = """"""$$"""""";");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = """
            $${|VirtualSpaces-4:|}
                """;
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesNotAtMiddle()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """""
            var v = """"$$""
            """"");
 
        testState.SendReturn(handled: false);
        testState.AssertCodeIs(
            """""
            var v = """"$$""
            """"");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotes_Interpolated()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = $"""$$"""
            """");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = $"""
            $${|VirtualSpaces-4:|}
                """
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesMoreQuotesLaterOn()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = """$$""";
            Console.WriteLine("Goo");
            """");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = """
            $${|VirtualSpaces-4:|}
                """;
            Console.WriteLine("Goo");
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesAsArgument1()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = WriteLine("""$$"""
            """");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = WriteLine("""
            $${|VirtualSpaces-4:|}
                """
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesAsArgument2()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = WriteLine(""""""$$"""""")");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = WriteLine("""
            $${|VirtualSpaces-4:|}
                """)
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesAsArgument3()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = WriteLine(""""""$$"""""");");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = WriteLine("""
            $${|VirtualSpaces-4:|}
                """);
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesAsArgument4()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = WriteLine(
                """$$"""
            """");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = WriteLine(
                """
            $${|VirtualSpaces-4:|}
                """
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesAsArgument5()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = WriteLine(
                """$$""")
            """");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = WriteLine(
                """
            $${|VirtualSpaces-4:|}
                """)
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesAsArgument6()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = WriteLine(
                """$$""");
            """");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = WriteLine(
                """
            $${|VirtualSpaces-4:|}
                """);
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesWithSemicolonAfter_Interpolated()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = $""""""$$"""""";");
 
        testState.SendReturn(handled: true);
        testState.AssertCodeIs(
            """"
            var v = $"""
            $${|VirtualSpaces-4:|}
                """;
            """");
    }
 
    [WpfFact]
    public void TestReturnInSixQuotesNotAtMiddle_Interpolated()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """""
            var v = $""""$$""
            """"");
 
        testState.SendReturn(handled: false);
        testState.AssertCodeIs(
            """""
            var v = $""""$$""
            """"");
    }
 
    [WpfFact]
    public void TestReturnEndOfFile()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = """"""$$");
 
        testState.SendReturn(handled: false);
    }
 
    [WpfFact]
    public void TestReturnInEmptyFile()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"$$");
 
        testState.SendReturn(handled: false);
    }
 
    #endregion
 
    #region generate initial empty raw string
 
    [WpfFact]
    public void TestGenerateAtEndOfFile()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = """"$$");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """"
            var v = """$$"""
            """");
    }
 
    [WpfFact]
    public void TestGenerateWithSemicolonAfter()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = """"$$;");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
@"var v = """"""$$"""""";");
    }
 
    [WpfFact]
    public void TestGenerateWithInterpolatedString()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = $""""$$");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """"
            var v = $"""$$"""
            """");
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/66538")]
    public void TestGenerateWithInterpolatedString_TwoDollarSigns()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
"""var v = $$""[||]""", withSpansOnly: true);
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
""""
var v = $$"""[||]"""
"""", withSpansOnly: true);
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/66538")]
    public void TestGenerateWithInterpolatedString_TwoDollarSigns_FourthDoubleQuote()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
""""var v = $$"""[||]""";"""", withSpansOnly: true);
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
"""""var v = $$""""[||]"""";""""", withSpansOnly: true);
    }
 
    [WpfFact, WorkItem("https://github.com/dotnet/roslyn/issues/66538")]
    public void TestGenerateWithInterpolatedString_ThreeDollarSigns()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
"""var v = $$$""[||]""", withSpansOnly: true);
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
""""
var v = $$$"""[||]"""
"""", withSpansOnly: true);
    }
 
    [WpfFact]
    public void TestNoGenerateWithVerbatimString()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = @""""$$");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
@"var v = @""""""$$");
    }
 
    [WpfFact]
    public void TestNoGenerateWithVerbatimInterpolatedString1()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = @$""""$$");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
@"var v = @$""""""$$");
    }
 
    [WpfFact]
    public void TestNoGenerateWithVerbatimInterpolatedString2()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = $@""""$$");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
@"var v = $@""""""$$");
    }
 
    #endregion
 
    #region grow empty raw string
 
    [WpfFact]
    public void TestDoNotGrowEmptyInsideSimpleString()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """
            var v = "$$"
            """);
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """
            var v = ""$$"
            """);
    }
 
    [WpfFact]
    public void TestDoNotGrowEmptyInsideFourQuotes()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """
            var v = ""$$""
            """);
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """"
            var v = """$$""
            """");
    }
 
    [WpfFact]
    public void TestDoGrowEmptyInsideSixQuotesInMiddle()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = """$$"""
            """");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """""
            var v = """"$$""""
            """"");
    }
 
    [WpfFact]
    public void TestDoGrowEmptyInsideSixQuotesInInterpolatedRaw()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = $"""$$"""
            """");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """""
            var v = $""""$$""""
            """"");
    }
 
    [WpfFact]
    public void TestDoNotGrowEmptyInsideSixQuotesWhenNotInMiddle1()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """""
            var v = $""$$""""
            """"");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """""
            var v = $"""$$""""
            """"");
    }
 
    #endregion
 
    #region grow delimiters
 
    [WpfFact]
    public void TestGrowDelimetersWhenEndExists_SingleLine()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = """$$ """
            """");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """""
            var v = """"$$ """"
            """"");
    }
 
    [WpfFact]
    public void TestGrowDelimetersWhenEndExists_MultiLine()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = """$$
 
                """
            """");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """""
            var v = """"$$
 
                """"
            """"");
    }
 
    [WpfFact]
    public void TestGrowDelimetersWhenEndExists_Interpolated()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = $"""$$
 
                """
            """");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """""
            var v = $""""$$
 
                """"
            """"");
    }
 
    [WpfFact]
    public void TestDoNotGrowDelimetersWhenEndNotThere()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"var v = """"""$$");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
@"var v = """"""""$$");
    }
 
    [WpfFact]
    public void TestDoNotGrowDelimetersWhenEndTooShort()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
            """"
            var v = """$$
 
                ""
            """");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """""
            var v = """"$$
 
                ""
            """"");
    }
 
    #endregion
 
    [WpfFact]
    public void TestTypeQuoteEmptyFile()
    {
        using var testState = RawStringLiteralTestState.CreateTestState(
@"$$");
 
        testState.SendTypeChar('"');
        testState.AssertCodeIs(
            """
            "$$
            """);
    }
}