|
// 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(
"""
"$$
""");
}
}
|