File: RawStringLiteral\RawStringLiteralCommandHandlerTests.cs
Web Access
Project: ..\..\..\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(
@"""$$");
        }
    }
}