protected void RunAutoInsertTest(string input, string expected, int tabSize = 4, bool insertSpaces = true, string fileKind = default, IReadOnlyList <TagHelperDescriptor> tagHelpers = default) { // Arrange TestFileMarkupParser.GetPosition(input, out input, out var location); var source = SourceText.From(input); source.GetLineAndOffset(location, out var line, out var column); var position = new Position(line, column); var path = "file:///path/to/document.razor"; var uri = new Uri(path); var codeDocument = CreateCodeDocument(source, uri.AbsolutePath, tagHelpers, fileKind: fileKind); var options = new FormattingOptions() { TabSize = tabSize, InsertSpaces = insertSpaces, }; var provider = CreateProvider(); var context = FormattingContext.Create(uri, Mock.Of <DocumentSnapshot>(MockBehavior.Strict), codeDocument, options, TestAdhocWorkspaceFactory.Instance); // Act if (!provider.TryResolveInsertion(position, context, out var edit, out _)) { edit = null; } // Assert var edited = edit is null ? source : ApplyEdit(source, edit); var actual = edited.ToString(); Assert.Equal(expected, actual); }
public async Task GetNavigatePositionAsync_TagHelperProperty_CorrectRange2() { // Arrange var content = @" <div>@Title</div> @code { [Microsoft.AspNetCore.Components.Parameter] public string [|Title|] { get; set; } } "; TestFileMarkupParser.GetSpan(content, out content, out var selection); SetupDocument(out var codeDocument, out _, content); var expectedRange = selection.AsRange(codeDocument.GetSourceText()); var mappingService = new DefaultRazorDocumentMappingService(LoggerFactory); // Act II var range = await RazorDefinitionEndpoint.TryGetPropertyRangeAsync(codeDocument, "Title", mappingService, Logger, CancellationToken.None).ConfigureAwait(false); Assert.NotNull(range); Assert.Equal(expectedRange, range); }
public async Task GetNavigatePositionAsync_TagHelperProperty_IgnoreInnerProperty() { // Arrange var content = @" <div>@Title</div> @code { private class NotTheDroidsYoureLookingFor { public string Title { get; set; } } public string [|Title|] { get; set; } } "; TestFileMarkupParser.GetSpan(content, out content, out var selection); SetupDocument(out var codeDocument, out _, content); var expectedRange = selection.AsRange(codeDocument.GetSourceText()); var mappingService = new DefaultRazorDocumentMappingService(LoggerFactory); // Act II var range = await RazorDefinitionEndpoint.TryGetPropertyRangeAsync(codeDocument, "Title", mappingService, Logger, CancellationToken.None).ConfigureAwait(false); Assert.NotNull(range); Assert.Equal(expectedRange, range); }
protected async Task RunOnTypeFormattingTestAsync(string input, string expected, int tabSize = 4, bool insertSpaces = true, string fileKind = null) { // Arrange fileKind ??= FileKinds.Component; TestFileMarkupParser.GetPosition(input, out input, out var beforeTrigger); var source = SourceText.From(input); var path = "file:///path/to/document.razor"; var uri = new Uri(path); var(codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(source, uri.AbsolutePath, fileKind: fileKind); var options = new FormattingOptions() { TabSize = tabSize, InsertSpaces = insertSpaces, }; var formattingService = CreateFormattingService(codeDocument); var(kind, projectedEdits) = GetFormattedEdits(codeDocument, expected, beforeTrigger); // Act var edits = await formattingService.ApplyFormattedEditsAsync(uri, documentSnapshot, kind, projectedEdits, options, CancellationToken.None); // Assert var edited = ApplyEdits(source, edits); var actual = edited.ToString(); new XUnitVerifier().EqualOrDiff(expected, actual); }
public async void FindsError_ForNameExpressions(string dataNameExpression) { TestFileMarkupParser.GetPositionsAndSpans(dataNameExpression, out var parsedDataNameExpression, out _, out _); var dataNameExpressionLength = parsedDataNameExpression.Length; await new Verify.Test { TestState = { Sources = { "public class TestClass {" + " const string DataNameConst = \"Data\";" + " const string DataNameofConst = nameof(Data);" + " private static System.Collections.Generic.IEnumerable<object[]> Data = null;" + " [Xunit.MemberData(" + dataNameExpression + ")] public void TestMethod() { }" + "}", "public static class OtherClass { public const string Data = \"Data\"; }", }, }, ExpectedDiagnostics = { Verify.Diagnostic("xUnit1016").WithSpan(1, 193, 1, 211 + dataNameExpressionLength).WithSeverity(DiagnosticSeverity.Error), }, }.RunAsync(); }
protected async Task RunCodeActionFormattingTestAsync( string input, TextEdit[] codeActionEdits, string expected, int tabSize = 4, bool insertSpaces = true, string?fileKind = null) { if (codeActionEdits is null) { throw new NotImplementedException("Code action formatting must provide edits."); } // Arrange fileKind ??= FileKinds.Component; TestFileMarkupParser.GetPosition(input, out input, out var positionAfterTrigger); var razorSourceText = SourceText.From(input); var path = "file:///path/to/Document.razor"; var uri = new Uri(path); var(codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(razorSourceText, uri.AbsolutePath, fileKind: fileKind); #pragma warning disable CS0618 // Type or member is obsolete var mappingService = new DefaultRazorDocumentMappingService(); #pragma warning restore CS0618 // Type or member is obsolete var languageKind = mappingService.GetLanguageKind(codeDocument, positionAfterTrigger); if (languageKind == RazorLanguageKind.Html) { throw new NotImplementedException("Code action formatting is not yet supported for HTML in Razor."); } if (!mappingService.TryMapToProjectedDocumentPosition(codeDocument, positionAfterTrigger, out _, out var _)) { throw new InvalidOperationException("Could not map from Razor document to generated document"); } var formattingService = CreateFormattingService(codeDocument); var options = new FormattingOptions() { TabSize = tabSize, InsertSpaces = insertSpaces, }; // Act var edits = await formattingService.FormatCodeActionAsync(uri, documentSnapshot, languageKind, codeActionEdits, options, CancellationToken.None); // Assert var edited = ApplyEdits(razorSourceText, edits); var actual = edited.ToString(); new XUnitVerifier().EqualOrDiff(expected, actual); }
protected void Test(string expected, string markupCode, bool completionActive = false, bool assertNextHandlerInvoked = false) { TestFileMarkupParser.GetPositionsAndSpans(markupCode, out var code, out var positions, out _); Assert.NotEmpty(positions); foreach (var position in positions) { // Run the test once for each input position. All marked positions in the input for a test are expected // to have the same result. Test(expected, code, position, completionActive, assertNextHandlerInvoked); } }
protected async Task <(SourceText, TextEdit[])> GetOnTypeFormattingEditsAsync( string input, char triggerCharacter, int tabSize = 4, bool insertSpaces = true, string fileKind = null) { // Arrange fileKind ??= FileKinds.Component; TestFileMarkupParser.GetPosition(input, out input, out var positionAfterTrigger); var razorSourceText = SourceText.From(input); var path = "file:///path/to/Document.razor"; var uri = new Uri(path); var(codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(razorSourceText, uri.AbsolutePath, fileKind: fileKind); var mappingService = new DefaultRazorDocumentMappingService(); var languageKind = mappingService.GetLanguageKind(codeDocument, positionAfterTrigger); if (!mappingService.TryMapToProjectedDocumentPosition(codeDocument, positionAfterTrigger, out _, out var projectedIndex)) { throw new InvalidOperationException("Could not map from Razor document to generated document"); } var projectedEdits = Array.Empty <TextEdit>(); if (languageKind == RazorLanguageKind.CSharp) { projectedEdits = await GetFormattedCSharpEditsAsync( codeDocument, triggerCharacter, projectedIndex, insertSpaces, tabSize).ConfigureAwait(false); } else if (languageKind == RazorLanguageKind.Html) { throw new NotImplementedException("OnTypeFormatting is not yet supported for HTML in Razor."); } var formattingService = CreateFormattingService(codeDocument); var options = new FormattingOptions() { TabSize = tabSize, InsertSpaces = insertSpaces, }; // Act var edits = await formattingService.ApplyFormattedEditsAsync( uri, documentSnapshot, languageKind, projectedEdits, options, CancellationToken.None); return(razorSourceText, edits); }
public static IEnumerable <object[]> GenerateDefineUsagesWithExplicitNumberOfArgs(string template, int numArgs) { TestFileMarkupParser.GetSpans(template, out _, out ImmutableDictionary <string, ImmutableArray <TextSpan> > spans); var spanCount = spans.Sum(pair => string.IsNullOrEmpty(pair.Key) ? 0 : pair.Value.Count()); var numberOfArguments = template.Count(c => c == '{') - spanCount; if (numArgs != -1) { numberOfArguments = numArgs; } yield return(new[] { $"LoggerMessage.{GenerateGenericInvocation(numberOfArguments, "DefineScope")}({template});" }); yield return(new[] { $"LoggerMessage.{GenerateGenericInvocation(numberOfArguments, "Define")}(LogLevel.Information, 42, {template});" }); }
protected async Task RunFormattingTestAsync( string input, string expected, int tabSize = 4, bool insertSpaces = true, string?fileKind = null, IReadOnlyList <TagHelperDescriptor>?tagHelpers = null, bool allowDiagnostics = false) { // Arrange fileKind ??= FileKinds.Component; TestFileMarkupParser.GetSpans(input, out input, out ImmutableArray <TextSpan> spans); var span = spans.IsEmpty ? new TextSpan(0, input.Length) : spans.Single(); var source = SourceText.From(input); var range = span.AsRange(source); var path = "file:///path/to/Document." + fileKind; var uri = new Uri(path); var(codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(source, uri.AbsolutePath, tagHelpers, fileKind, allowDiagnostics); var options = new FormattingOptions() { TabSize = tabSize, InsertSpaces = insertSpaces, }; var formattingService = CreateFormattingService(codeDocument); // Act var edits = await formattingService.FormatAsync(uri, documentSnapshot, range, options, CancellationToken.None); // Assert var edited = ApplyEdits(source, edits); var actual = edited.ToString(); new XUnitVerifier().EqualOrDiff(expected, actual); if (input.Equals(expected)) { Assert.Empty(edits); } }
protected async Task RunOnTypeFormattingTestAsync( string input, string expected, char triggerCharacter, int tabSize = 4, bool insertSpaces = true, string?fileKind = null) { // Arrange fileKind ??= FileKinds.Component; TestFileMarkupParser.GetPosition(input, out input, out var positionAfterTrigger); var razorSourceText = SourceText.From(input); var path = "file:///path/to/Document.razor"; var uri = new Uri(path); var(codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(razorSourceText, uri.AbsolutePath, fileKind: fileKind); var mappingService = new DefaultRazorDocumentMappingService(LoggerFactory); var languageKind = mappingService.GetLanguageKind(codeDocument, positionAfterTrigger); var formattingService = CreateFormattingService(codeDocument); var options = new FormattingOptions() { TabSize = tabSize, InsertSpaces = insertSpaces, }; // Act var edits = await formattingService.FormatOnTypeAsync(uri, documentSnapshot, languageKind, Array.Empty <TextEdit>(), options, hostDocumentIndex : positionAfterTrigger, triggerCharacter : triggerCharacter, CancellationToken.None); // Assert var edited = ApplyEdits(razorSourceText, edits); var actual = edited.ToString(); new XUnitVerifier().EqualOrDiff(expected, actual); if (input.Equals(expected)) { Assert.Empty(edits); } }
protected async Task RunFormattingTestAsync( string input, string expected, int tabSize = 4, bool insertSpaces = true, string fileKind = null, IReadOnlyList <TagHelperDescriptor> tagHelpers = null) { // Arrange fileKind ??= FileKinds.Component; TestFileMarkupParser.GetSpans(input, out input, out ImmutableArray <TextSpan> spans); var span = spans.IsEmpty ? new TextSpan(0, input.Length) : spans.Single(); var source = SourceText.From(input); var range = span.AsRange(source); var path = "file:///path/to/document.razor"; var uri = new Uri(path); var(codeDocument, documentSnapshot) = CreateCodeDocumentAndSnapshot(source, uri.AbsolutePath, tagHelpers, fileKind); var options = new FormattingOptions() { TabSize = tabSize, InsertSpaces = insertSpaces, }; var formattingService = CreateFormattingService(codeDocument); // Act var edits = await formattingService.FormatAsync(uri, documentSnapshot, range, options, CancellationToken.None); // Assert var edited = ApplyEdits(source, edits); var actual = edited.ToString(); #if GENERATE_BASELINES Assert.False(true, "GENERATE_BASELINES is set to true."); #else Assert.Equal(expected, actual, ignoreLineEndingDifferences: true); #endif }
protected async Task VerifyRefactoringAsync(string sourceWithMarkup, string expected, CancellationToken cancellationToken = default) { TestFileMarkupParser.GetPositionAndSpans(sourceWithMarkup, out string source, cursorPosition: out _, out IList <TextSpan> textSpans); var textSpan = Assert.Single(textSpans); var document = CreateDocument(source, LanguageNames.CSharp); var actions = new List <CodeAction>(); var context = new CodeRefactoringContext(document, textSpan, (a) => actions.Add(a), cancellationToken); var codeRefactoringProvider = GetCodeRefactoringProvider(); await codeRefactoringProvider.ComputeRefactoringsAsync(context); var codeAction = actions.First(); var operations = await codeAction.GetOperationsAsync(cancellationToken); var solution = operations.OfType <ApplyChangesOperation>().Single().ChangedSolution; document = solution.GetDocument(document.Id); var newDocumentString = getStringFromDocument(document); Assert.Equal(expected, newDocumentString);
private static TestHostDocument CreateDocument( TestWorkspace workspace, XElement workspaceElement, XElement documentElement, ExportProvider exportProvider, HostLanguageServices languageServiceProvider, IDocumentServiceProvider documentServiceProvider, ref int documentId) { var isLinkFileAttribute = documentElement.Attribute(IsLinkFileAttributeName); var isLinkFile = isLinkFileAttribute != null && ((bool?)isLinkFileAttribute).HasValue && ((bool?)isLinkFileAttribute).Value; if (isLinkFile) { // This is a linked file. Use the filePath and markup from the referenced document. var originalAssemblyName = documentElement.Attribute(LinkAssemblyNameAttributeName)?.Value; var originalProjectName = documentElement.Attribute(LinkProjectNameAttributeName)?.Value; if (originalAssemblyName == null && originalProjectName == null) { throw new ArgumentException($"Linked files must specify either a {LinkAssemblyNameAttributeName} or {LinkProjectNameAttributeName}"); } var originalProject = workspaceElement.Elements(ProjectElementName).FirstOrDefault(p => { if (originalAssemblyName != null) { return(p.Attribute(AssemblyNameAttributeName)?.Value == originalAssemblyName); } else { return(p.Attribute(ProjectNameAttribute)?.Value == originalProjectName); } }); if (originalProject == null) { if (originalProjectName != null) { throw new ArgumentException($"Linked file's {LinkProjectNameAttributeName} '{originalProjectName}' project not found."); } else { throw new ArgumentException($"Linked file's {LinkAssemblyNameAttributeName} '{originalAssemblyName}' project not found."); } } var originalDocumentPath = documentElement.Attribute(LinkFilePathAttributeName)?.Value; if (originalDocumentPath == null) { throw new ArgumentException($"Linked files must specify a {LinkFilePathAttributeName}"); } documentElement = originalProject.Elements(DocumentElementName).FirstOrDefault(d => { return(d.Attribute(FilePathAttributeName)?.Value == originalDocumentPath); }); if (documentElement == null) { throw new ArgumentException($"Linked file's LinkFilePath '{originalDocumentPath}' file not found."); } } var markupCode = documentElement.NormalizedValue(); var fileName = GetFileName(workspace, documentElement, ref documentId); var folders = GetFolders(documentElement); var optionsElement = documentElement.Element(ParseOptionsElementName); // TODO: Allow these to be specified. var codeKind = SourceCodeKind.Regular; if (optionsElement != null) { var attr = optionsElement.Attribute(KindAttributeName); codeKind = attr == null ? SourceCodeKind.Regular : (SourceCodeKind)Enum.Parse(typeof(SourceCodeKind), attr.Value); } TestFileMarkupParser.GetPositionAndSpans(markupCode, out var code, out int?cursorPosition, out ImmutableDictionary <string, ImmutableArray <TextSpan> > spans); var testDocumentServiceProvider = GetDocumentServiceProvider(documentElement); if (documentServiceProvider == null) { documentServiceProvider = testDocumentServiceProvider; } else if (testDocumentServiceProvider != null) { AssertEx.Fail($"The document attributes on file {fileName} conflicted"); } return(new TestHostDocument( exportProvider, languageServiceProvider, code, fileName, fileName, cursorPosition, spans, codeKind, folders, isLinkFile, documentServiceProvider)); }