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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
        }
Пример #5
0
        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
        }
Пример #13
0
        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));
        }