private LSPDocumentMappingProvider GetDocumentMappingProvider(Range expectedRange, int expectedVersion, RazorLanguageKind languageKind) { var remappingResult = new RazorMapToDocumentRangesResponse() { Ranges = new[] { expectedRange } }; var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(MockBehavior.Strict); documentMappingProvider.Setup(d => d.MapToDocumentRangesAsync(languageKind, Uri, It.IsAny <Range[]>(), It.IsAny <CancellationToken>())). Returns(Task.FromResult(remappingResult)); return(documentMappingProvider.Object); }
public async Task MapSpans_WithinRange_ReturnsMapping() { // Arrange var called = false; var textSpan = new TextSpan(1, 10); var spans = new TextSpan[] { textSpan }; var documentSnapshot = new Mock <LSPDocumentSnapshot>(MockBehavior.Strict); documentSnapshot.SetupGet(doc => doc.Uri).Returns(_mockDocumentUri); var textSnapshot = new StringTextSnapshot(s_mockGeneratedContent, 1); var textSpanAsRange = textSpan.AsRange(_sourceTextGenerated); var mappedRange = new Range() { Start = new Position(2, 1), End = new Position(2, 11) }; var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(MockBehavior.Strict); var mappingResult = new RazorMapToDocumentRangesResponse() { Ranges = new Range[] { mappedRange } }; documentMappingProvider.Setup(dmp => dmp.MapToDocumentRangesAsync(It.IsAny <RazorLanguageKind>(), It.IsAny <Uri>(), It.IsAny <Range[]>(), It.IsAny <CancellationToken>())) .Callback <RazorLanguageKind, Uri, Range[], CancellationToken>((languageKind, uri, ranges, ct) => { Assert.Equal(RazorLanguageKind.CSharp, languageKind); Assert.Equal(_mockDocumentUri, uri); Assert.Single(ranges, textSpanAsRange); called = true; }) .Returns(Task.FromResult(mappingResult)); var service = new RazorLSPSpanMappingService(documentMappingProvider.Object, documentSnapshot.Object, textSnapshot); var expectedSpan = mappedRange.AsTextSpan(_sourceTextRazor); var expectedLinePosition = _sourceTextRazor.Lines.GetLinePositionSpan(expectedSpan); var expectedFilePath = _mockDocumentUri.LocalPath; var expectedResult = (expectedFilePath, expectedLinePosition, expectedSpan); // Act var result = await service.MapSpansAsyncTest(spans, _sourceTextGenerated, _sourceTextRazor).ConfigureAwait(false); // Assert Assert.True(called); Assert.Single(result, expectedResult); }
public void MapSpans_GetMappedSpanResults_MappingErrorReturnsDefaultMappedSpan() { // Arrange var documentSnapshot = new Mock <LSPDocumentSnapshot>(MockBehavior.Strict); documentSnapshot.SetupGet(doc => doc.Uri).Returns(_mockDocumentUri); var sourceTextRazor = SourceText.From(""); var response = new RazorMapToDocumentRangesResponse { Ranges = new Range[] { Extensions.RangeExtensions.UndefinedRange } }; // Act var results = RazorLSPSpanMappingService.GetMappedSpanResults(documentSnapshot.Object, sourceTextRazor, response); // Assert Assert.True(results.Single().IsDefault); }
public async Task RazorMapToDocumentRangeAsync_InvokesLanguageServer() { // Arrange var uri = new Uri("file:///some/folder/to/file.razor"); var response = new RazorMapToDocumentRangesResponse() { Ranges = new[] { new Range() { Start = new Position(1, 1), End = new Position(3, 3), } }, HostDocumentVersion = 1 }; var requestInvoker = new Mock <LSPRequestInvoker>(MockBehavior.Strict); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <RazorMapToDocumentRangesParams, RazorMapToDocumentRangesResponse>( It.IsAny <ITextBuffer>(), LanguageServerConstants.RazorMapToDocumentRangesEndpoint, RazorLSPConstants.RazorLanguageServerName, It.IsAny <Func <JToken, bool> >(), It.IsAny <RazorMapToDocumentRangesParams>(), It.IsAny <CancellationToken>())) .Returns(Task.FromResult(new ReinvocationResponse <RazorMapToDocumentRangesResponse>("TestLanguageClient", response))); var mappingProvider = new DefaultLSPDocumentMappingProvider(requestInvoker.Object, DocumentManager); var projectedRange = new Range() { Start = new Position(10, 10), End = new Position(15, 15) }; // Act var result = await mappingProvider.MapToDocumentRangesAsync(RazorLanguageKind.CSharp, uri, new[] { projectedRange }, CancellationToken.None).ConfigureAwait(false); // Assert Assert.NotNull(result); Assert.Equal(1, result.HostDocumentVersion); var actualRange = result.Ranges[0]; Assert.Equal(new Position(1, 1), actualRange.Start); Assert.Equal(new Position(3, 3), actualRange.End); }
public async Task HandleRequestAsync_CSharpProjection_InvokesCSharpLanguageServer() { // Arrange var called = false; var expectedContents = new SumType <SumType <string, MarkedString>, SumType <string, MarkedString>[], MarkupContent>( new MarkedString() { Language = "markdown", Value = "Hover Details" } ); var lspResponse = new Hover() { Range = new Range() { Start = new Position(10, 0), End = new Position(10, 1) }, Contents = expectedContents }; var expectedItem = new Hover() { Range = new Range() { Start = new Position(0, 0), End = new Position(0, 1) }, Contents = expectedContents }; var hoverRequest = new TextDocumentPositionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(0, 1) }; var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>()); var requestInvoker = new Mock <LSPRequestInvoker>(); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, Hover>(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <TextDocumentPositionParams>(), It.IsAny <CancellationToken>())) .Callback <string, string, TextDocumentPositionParams, CancellationToken>((method, serverContentType, hoverParams, ct) => { Assert.Equal(Methods.TextDocumentHoverName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }) .Returns(Task.FromResult(lspResponse)); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp }; var projectionProvider = new Mock <LSPProjectionProvider>(); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var remappingResult = new RazorMapToDocumentRangesResponse() { Ranges = new[] { new Range() { Start = new Position(0, 0), End = new Position(0, 1) } }, HostDocumentVersion = 0 }; var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(); documentMappingProvider.Setup(d => d.MapToDocumentRangesAsync(RazorLanguageKind.CSharp, It.IsAny <Uri>(), It.IsAny <Range[]>(), It.IsAny <CancellationToken>())). Returns(Task.FromResult(remappingResult)); var hoverHandler = new HoverHandler(requestInvoker.Object, documentManager, projectionProvider.Object, documentMappingProvider.Object); // Act var result = await hoverHandler.HandleRequestAsync(hoverRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(called); Assert.Equal(expectedItem.Contents, result.Contents); Assert.Equal(expectedItem.Range, result.Range); }
public async Task HandleRequestAsync_HtmlProjection_InvokesHtmlLanguageServer() { // Arrange var lspFarEndpointCalled = false; var progressReported = false; var expectedUri1 = new Uri("C:/path/to/file1.razor"); var expectedUri2 = new Uri("C:/path/to/file2.razor"); var expectedLocation1 = GetReferenceItem(5, expectedUri1); var expectedLocation2 = GetReferenceItem(10, expectedUri2); var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>()); var virtualHtmlUri1 = new Uri("C:/path/to/file1.razor__virtual.html"); var virtualHtmlUri2 = new Uri("C:/path/to/file2.razor__virtual.html"); var htmlLocation1 = GetReferenceItem(100, virtualHtmlUri1); var htmlLocation2 = GetReferenceItem(200, virtualHtmlUri2); var languageServiceBroker = Mock.Of <ILanguageServiceBroker2>(); using var lspProgressListener = new DefaultLSPProgressListener(languageServiceBroker); var token = Guid.NewGuid().ToString(); var parameterToken = new JObject { { "token", token }, { "value", JArray.FromObject(new[] { htmlLocation1, htmlLocation2 }) } }; var requestInvoker = new Mock <LSPRequestInvoker>(); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, VSReferenceItem[]>(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <TextDocumentPositionParams>(), It.IsAny <CancellationToken>())) .Callback <string, string, TextDocumentPositionParams, CancellationToken>((method, serverContentType, definitionParams, ct) => { Assert.Equal(Methods.TextDocumentReferencesName, method); Assert.Equal(RazorLSPConstants.HtmlLSPContentTypeName, serverContentType); lspFarEndpointCalled = true; _ = lspProgressListener.ProcessProgressNotificationAsync(Methods.ProgressNotificationName, parameterToken); }) .Returns(Task.FromResult(Array.Empty <VSReferenceItem>())); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Html, }; var projectionProvider = new Mock <LSPProjectionProvider>(); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var remappingResult1 = new RazorMapToDocumentRangesResponse() { Ranges = new[] { expectedLocation1.Location.Range } }; var remappingResult2 = new RazorMapToDocumentRangesResponse() { Ranges = new[] { expectedLocation2.Location.Range } }; var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(); documentMappingProvider .Setup(d => d.MapToDocumentRangesAsync(RazorLanguageKind.Html, It.IsAny <Uri>(), It.IsAny <Range[]>(), It.IsAny <CancellationToken>())) .Returns <RazorLanguageKind, Uri, Range[], CancellationToken>((languageKind, uri, ranges, ct) => Task.FromResult(uri.LocalPath.Contains("file1") ? remappingResult1 : remappingResult2)); var referencesHandler = new FindAllReferencesHandler(requestInvoker.Object, documentManager, projectionProvider.Object, documentMappingProvider.Object, lspProgressListener); referencesHandler.WaitForProgressNotificationTimeout = TestWaitForProgressNotificationTimeout; var progressToken = new ProgressWithCompletion <object>((val) => { var results = Assert.IsType <VSReferenceItem[]>(val); Assert.Collection(results, a => AssertVSReferenceItem(expectedLocation1, a), b => AssertVSReferenceItem(expectedLocation2, b)); progressReported = true; }); var referenceRequest = new ReferenceParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5), PartialResultToken = progressToken }; // Act var result = await referencesHandler.HandleRequestAsync(referenceRequest, new ClientCapabilities(), token, CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(lspFarEndpointCalled); Assert.True(progressReported); }
public async Task HandleRequestAsync_LargeProject_InvokesCSharpLanguageServer() { // Validates batching mechanism for the progress notification on large projects // Arrange var lspFarEndpointCalled = false; const int BATCH_SIZE = 10; const int NUM_BATCHES = 10; const int NUM_DOCUMENTS = BATCH_SIZE * NUM_BATCHES; const int MAPPING_OFFSET = 10; var expectedUris = new Uri[NUM_DOCUMENTS]; var virtualUris = new Uri[NUM_DOCUMENTS]; var expectedReferences = new VSReferenceItem[NUM_BATCHES][]; var csharpUnmappedReferences = new VSReferenceItem[NUM_BATCHES][]; var parameterTokens = new JObject[NUM_BATCHES]; var token = Guid.NewGuid().ToString(); var documentNumber = 0; for (var batch = 0; batch < NUM_BATCHES; ++batch) { expectedReferences[batch] = new VSReferenceItem[BATCH_SIZE]; csharpUnmappedReferences[batch] = new VSReferenceItem[BATCH_SIZE]; for (var documentInBatch = 0; documentInBatch < BATCH_SIZE; ++documentInBatch) { expectedUris[documentNumber] = new Uri($"C:/path/to/file{documentNumber}.razor"); virtualUris[documentNumber] = new Uri($"C:/path/to/file{documentNumber}.razor.g.cs"); expectedReferences[batch][documentInBatch] = GetReferenceItem(documentNumber, expectedUris[documentNumber]); var umappedOffset = documentNumber * MAPPING_OFFSET; csharpUnmappedReferences[batch][documentInBatch] = GetReferenceItem(umappedOffset, virtualUris[documentNumber]); documentNumber++; } parameterTokens[batch] = new JObject { { "token", token }, { "value", JArray.FromObject(csharpUnmappedReferences[batch]) } }; } var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>()); var languageServiceBroker = Mock.Of <ILanguageServiceBroker2>(); using var lspProgressListener = new DefaultLSPProgressListener(languageServiceBroker); var requestInvoker = new Mock <LSPRequestInvoker>(); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, VSReferenceItem[]>(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <TextDocumentPositionParams>(), It.IsAny <CancellationToken>())) .Callback <string, string, TextDocumentPositionParams, CancellationToken>((method, serverContentType, definitionParams, ct) => { Assert.Equal(Methods.TextDocumentReferencesName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); lspFarEndpointCalled = true; for (var i = 0; i < NUM_BATCHES; ++i) { _ = lspProgressListener.ProcessProgressNotificationAsync(Methods.ProgressNotificationName, parameterTokens[i]); } }) .Returns(Task.FromResult(Array.Empty <VSReferenceItem>())); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp, }; var projectionProvider = new Mock <LSPProjectionProvider>(); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(); documentMappingProvider .Setup(d => d.MapToDocumentRangesAsync(RazorLanguageKind.CSharp, It.IsAny <Uri>(), It.IsAny <Range[]>(), It.IsAny <CancellationToken>())) .Returns <RazorLanguageKind, Uri, Range[], CancellationToken>((languageKind, uri, ranges, ct) => { var unmappedPosition = ranges[0].Start.Line; var mappedPosition = unmappedPosition / MAPPING_OFFSET; var mappedRange = new Range() { Start = new Position(mappedPosition, mappedPosition), End = new Position(mappedPosition, mappedPosition) }; var response = new RazorMapToDocumentRangesResponse() { Ranges = new[] { mappedRange } }; return(Task.FromResult(response)); }); var referencesHandler = new FindAllReferencesHandler(requestInvoker.Object, documentManager, projectionProvider.Object, documentMappingProvider.Object, lspProgressListener); referencesHandler.WaitForProgressNotificationTimeout = TestWaitForProgressNotificationTimeout; var progressBatchesReported = new ConcurrentBag <VSReferenceItem[]>(); var progressToken = new ProgressWithCompletion <object>((val) => { var results = Assert.IsType <VSReferenceItem[]>(val); Assert.Equal(BATCH_SIZE, results.Length); progressBatchesReported.Add(results); }); var referenceRequest = new ReferenceParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5), PartialResultToken = progressToken }; // Act var result = await referencesHandler.HandleRequestAsync(referenceRequest, new ClientCapabilities(), token, CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(lspFarEndpointCalled); var sortedBatchesReported = progressBatchesReported.ToList(); sortedBatchesReported.Sort((VSReferenceItem[] a, VSReferenceItem[] b) => { var indexA = a[0].Location.Range.Start.Character; var indexB = b[0].Location.Range.Start.Character; return(indexA.CompareTo(indexB)); }); Assert.Equal(NUM_BATCHES, sortedBatchesReported.Count); for (var batch = 0; batch < NUM_BATCHES; ++batch) { for (var documentInBatch = 0; documentInBatch < BATCH_SIZE; ++documentInBatch) { AssertVSReferenceItem( expectedReferences[batch][documentInBatch], sortedBatchesReported[batch][documentInBatch]); } } }
public async Task HandleRequestAsync_VersionMismatch_DiscardsExternalRazorFiles() { // Arrange var progressReported = false; var externalUri = new Uri("C:/path/to/someotherfile.razor"); var expectedLocation = GetReferenceItem(5, externalUri); var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(d => d.Version == 2)); documentManager.AddDocument(externalUri, Mock.Of <LSPDocumentSnapshot>(d => d.Version == 5)); var virtualCSharpUri = new Uri("C:/path/to/someotherfile.razor.g.cs"); var csharpLocation = GetReferenceItem(100, virtualCSharpUri); var(requestInvoker, progressListener) = MockServices(csharpLocation, out var token); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp, }; var projectionProvider = new Mock <LSPProjectionProvider>(); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var remappingResult = new RazorMapToDocumentRangesResponse() { Ranges = new[] { expectedLocation.Location.Range }, HostDocumentVersion = 6 }; var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(); documentMappingProvider.Setup(d => d.MapToDocumentRangesAsync(RazorLanguageKind.CSharp, externalUri, new[] { csharpLocation.Location.Range }, It.IsAny <CancellationToken>())). Returns(Task.FromResult(remappingResult)); var languageServiceBroker = Mock.Of <ILanguageServiceBroker2>(); var referencesHandler = new FindAllReferencesHandler(requestInvoker, documentManager, projectionProvider.Object, documentMappingProvider.Object, progressListener); referencesHandler.WaitForProgressNotificationTimeout = TestWaitForProgressNotificationTimeout; var progressToken = new ProgressWithCompletion <object>((val) => { var results = Assert.IsType <VSReferenceItem[]>(val); Assert.Empty(results); progressReported = true; }); var referenceRequest = new ReferenceParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5), PartialResultToken = progressToken }; // Act var result = await referencesHandler.HandleRequestAsync(referenceRequest, new ClientCapabilities(), token, CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(progressReported); Assert.Empty(result); }
public async Task HandleRequestAsync_CSharpProjection_FiltersReferenceClassifiedRuns() { // Arrange var progressReported = false; var externalUri = new Uri("C:/path/to/someotherfile.razor"); var expectedClassifiedRun = new ClassifiedTextElement(new ClassifiedTextRun[] { new ClassifiedTextRun("text", "counter"), }); var expectedReferenceItem = GetReferenceItem(5, 5, 5, 5, externalUri, text: expectedClassifiedRun); var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(d => d.Version == 2)); documentManager.AddDocument(externalUri, Mock.Of <LSPDocumentSnapshot>(d => d.Version == 5)); var virtualClassifiedRun = new ClassifiedTextElement(new ClassifiedTextRun[] { new ClassifiedTextRun("field name", "__o"), new ClassifiedTextRun("text", " "), new ClassifiedTextRun("operator", "="), new ClassifiedTextRun("text", " "), new ClassifiedTextRun("text", "counter"), new ClassifiedTextRun("punctuation", ";"), }); var virtualCSharpUri = new Uri("C:/path/to/someotherfile.razor.g.cs"); var csharpLocation = GetReferenceItem(100, 100, 100, 100, virtualCSharpUri, text: virtualClassifiedRun); var(requestInvoker, progressListener) = MockServices(csharpLocation, out var token); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp, }; var projectionProvider = new Mock <LSPProjectionProvider>(); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var remappingResult = new RazorMapToDocumentRangesResponse() { Ranges = new[] { expectedReferenceItem.Location.Range }, HostDocumentVersion = 5 }; var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(); documentMappingProvider.Setup(d => d.MapToDocumentRangesAsync(RazorLanguageKind.CSharp, externalUri, new[] { csharpLocation.Location.Range }, It.IsAny <CancellationToken>())). Returns(Task.FromResult(remappingResult)); var referencesHandler = new FindAllReferencesHandler(requestInvoker, documentManager, projectionProvider.Object, documentMappingProvider.Object, progressListener); referencesHandler.WaitForProgressNotificationTimeout = TestWaitForProgressNotificationTimeout; var progressToken = new ProgressWithCompletion <object>((val) => { var results = Assert.IsType <VSReferenceItem[]>(val); var actualReferenceItem = Assert.Single(results); AssertVSReferenceItem(expectedReferenceItem, actualReferenceItem); progressReported = true; }); var referenceRequest = new ReferenceParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5), PartialResultToken = progressToken }; // Act var result = await referencesHandler.HandleRequestAsync(referenceRequest, new ClientCapabilities(), token, CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(progressReported); }