public async Task HandleRequestAsync_RazorProjection_DoesNotInvokeServer() { // Arrange var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(s => s.Uri == Uri)); var invokedServer = false; var requestInvoker = new Mock <LSPRequestInvoker>(); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <DocumentOnAutoInsertParams, DocumentOnAutoInsertResponseItem>(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <DocumentOnAutoInsertParams>(), It.IsAny <CancellationToken>())) .Callback <string, string, DocumentOnAutoInsertParams, CancellationToken>((method, serverContentType, formattingParams, ct) => { invokedServer = true; }) .Returns(Task.FromResult(new DocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() })); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Razor, }; 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 = Mock.Of <LSPDocumentMappingProvider>(); var handler = new OnAutoInsertHandler(documentManager, requestInvoker.Object, projectionProvider.Object, documentMappingProvider); var request = new DocumentOnAutoInsertParams() { Character = ">", TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Options = new FormattingOptions() { OtherOptions = new Dictionary <string, object>() }, Position = new Position(0, 0) }; // Act var response = await handler.HandleRequestAsync(request, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.False(invokedServer); Assert.Null(response); }
public async Task HandleRequestAsync_InvokesServerWithCorrectKey() { // Arrange var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(s => s.Uri == Uri)); var invokedServer = false; var requestInvoker = new Mock <LSPRequestInvoker>(); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <DocumentOnTypeFormattingParams, TextEdit[]>(It.IsAny <string>(), It.IsAny <LanguageServerKind>(), It.IsAny <DocumentOnTypeFormattingParams>(), It.IsAny <CancellationToken>())) .Callback <string, LanguageServerKind, DocumentOnTypeFormattingParams, CancellationToken>((method, serverKind, formattingParams, ct) => { Assert.True(formattingParams.Options.OtherOptions.ContainsKey(LanguageServerConstants.ExpectsCursorPlaceholderKey)); invokedServer = true; }) .Returns(Task.FromResult <TextEdit[]>(new[] { new TextEdit() })); 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 documentMappingProvider = Mock.Of <LSPDocumentMappingProvider>(); var editorService = Mock.Of <LSPEditorService>(); var handler = new TestOnTypeFormattingHandler(JoinableTaskContext, documentManager, requestInvoker.Object, projectionProvider.Object, documentMappingProvider, editorService); var request = new DocumentOnTypeFormattingParams() { Character = ">", TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Options = new FormattingOptions() { OtherOptions = new Dictionary <string, object>() }, Position = new Position(0, 0) }; // Act var edits = await handler.HandleRequestAsync(request, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(invokedServer); Assert.Empty(edits); }
public async Task HandleRequestAsync_CSharpProjection_DoesNotRemapNonRazorFiles() { // Arrange var progressReported = false; var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>()); var externalCSharpUri = new Uri("C:/path/to/someotherfile.cs"); var externalCsharpLocation = GetReferenceItem(100, externalCSharpUri); var(requestInvoker, progressListener) = MockServices(externalCsharpLocation, 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 documentMappingProvider = Mock.Of <LSPDocumentMappingProvider>(); var languageServiceBroker = Mock.Of <ILanguageServiceBroker2>(); var referencesHandler = new FindAllReferencesHandler(requestInvoker, documentManager, projectionProvider.Object, documentMappingProvider, progressListener); referencesHandler.WaitForProgressNotificationTimeout = TestWaitForProgressNotificationTimeout; var progressToken = new ProgressWithCompletion <object>((val) => { var results = Assert.IsType <VSReferenceItem[]>(val); var actualLocation = Assert.Single(results); AssertVSReferenceItem(externalCsharpLocation, actualLocation); 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); }
public async Task HandleRequestAsync_CSharpProjection_InvokesCSharpLanguageServer() { // Arrange var called = false; var expectedEdit = new TextEdit(); var documentManager = new TestDocumentManager(); var snapshot = new StringTextSnapshot(@" @code { public string _foo; }"); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(m => m.Snapshot == snapshot)); var requestInvoker = new Mock <LSPRequestInvoker>(); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <DocumentOnTypeFormattingParams, TextEdit[]>(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <DocumentOnTypeFormattingParams>(), It.IsAny <CancellationToken>())) .Callback <string, string, DocumentOnTypeFormattingParams, CancellationToken>((method, serverContentType, onTypeFormattingParams, ct) => { Assert.Equal(Methods.TextDocumentOnTypeFormattingName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }) .Returns(Task.FromResult(new[] { expectedEdit })); 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 mappingProvider = Mock.Of <LSPDocumentMappingProvider>(); var formatOnTypeHandler = new OnTypeFormattingHandler(documentManager, requestInvoker.Object, projectionProvider.Object, mappingProvider); var formattingRequest = new DocumentOnTypeFormattingParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(2, 19), Character = ";", Options = new FormattingOptions() }; // Act var result = await formatOnTypeHandler.HandleRequestAsync(formattingRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(called); }
public async Task HandleRequestAsync_HtmlProjection_InvokesHtmlLanguageServer_ReturnsItem() { // Arrange var called = false; var expectedResult = new ReinvocationResponse <SignatureHelp>("LanguageClientName", new SignatureHelp()); var virtualHtmlUri = new Uri("C:/path/to/file.razor__virtual.html"); var requestInvoker = new Mock <LSPRequestInvoker>(MockBehavior.Strict); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, SignatureHelp>( It.IsAny <ITextBuffer>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <TextDocumentPositionParams>(), It.IsAny <CancellationToken>())) .Callback <ITextBuffer, string, string, TextDocumentPositionParams, CancellationToken>((textBuffer, method, clientName, definitionParams, ct) => { Assert.Equal(Methods.TextDocumentSignatureHelpName, method); Assert.Equal(RazorLSPConstants.HtmlLanguageServerName, clientName); called = true; }) .Returns(Task.FromResult(expectedResult)); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Html, }; var projectionProvider = new Mock <LSPProjectionProvider>(MockBehavior.Strict); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var signatureHelpHandler = new SignatureHelpHandler(requestInvoker.Object, DocumentManager, projectionProvider.Object, LoggerProvider); var signatureHelpRequest = new TextDocumentPositionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await signatureHelpHandler.HandleRequestAsync(signatureHelpRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(called); Assert.Equal(expectedResult.Response, result); }
public async Task HandleRequestAsync_CSharpProjection_InvokesCSharpLanguageServerWithNoResult() { // Arrange var called = false; 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 <Hover>(null)); 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>(); 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.Null(result); }
public async Task HandleRequestAsync_CSharpProjection_InvokesCSharpLanguageServer_ReturnsItem() { // Arrange var called = false; var expectedResult = new SignatureHelp(); var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>()); var virtualCSharpUri = new Uri("C:/path/to/file.razor.g.cs"); var requestInvoker = new Mock <LSPRequestInvoker>(MockBehavior.Strict); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, SignatureHelp>(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <TextDocumentPositionParams>(), It.IsAny <CancellationToken>())) .Callback <string, string, TextDocumentPositionParams, CancellationToken>((method, serverContentType, definitionParams, ct) => { Assert.Equal(Methods.TextDocumentSignatureHelpName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }) .Returns(Task.FromResult(expectedResult)); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp, }; var projectionProvider = new Mock <LSPProjectionProvider>(MockBehavior.Strict); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var signatureHelpHandler = new SignatureHelpHandler(requestInvoker.Object, documentManager, projectionProvider.Object); var signatureHelpRequest = new TextDocumentPositionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await signatureHelpHandler.HandleRequestAsync(signatureHelpRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(called); Assert.Equal(expectedResult, result); }
public async Task HandleRequestAsync_RemapFailure_DiscardsLocation() { // Arrange var called = false; var expectedHighlight = GetHighlight(5, 5, 5, 5); var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(d => d.Version == 0, MockBehavior.Strict)); var csharpHighlight = GetHighlight(100, 100, 100, 100); var requestInvoker = GetRequestInvoker <DocumentHighlightParams, DocumentHighlight[]>( new[] { csharpHighlight }, (method, serverContentType, highlightParams, ct) => { Assert.Equal(Methods.TextDocumentDocumentHighlightName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp, }; var projectionProvider = GetProjectionProvider(projectionResult); var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(MockBehavior.Strict).Object; Mock.Get(documentMappingProvider).Setup(p => p.MapToDocumentRangesAsync(RazorLanguageKind.CSharp, Uri, It.IsAny <Range[]>(), CancellationToken.None)) .Returns(Task.FromResult <RazorMapToDocumentRangesResponse>(null)); var highlightHandler = new DocumentHighlightHandler(requestInvoker, documentManager, projectionProvider, documentMappingProvider); var highlightRequest = new DocumentHighlightParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await highlightHandler.HandleRequestAsync(highlightRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(called); Assert.Empty(result); }
public async Task HandleRequestAsync_RemapFailure_ReturnsNull() { // Arrange var invokerCalled = false; var expectedResponse = GetMatchingHTMLBracketRange(5); var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(d => d.Version == 0, MockBehavior.Strict)); var htmlResponse = GetMatchingHTMLBracketRange(10); var requestInvoker = GetRequestInvoker <DocumentOnTypeRenameParams, DocumentOnTypeRenameResponseItem>( htmlResponse, (method, serverContentType, highlightParams, ct) => { Assert.Equal(MSLSPMethods.OnTypeRenameName, method); Assert.Equal(RazorLSPConstants.HtmlLSPContentTypeName, serverContentType); invokerCalled = true; }); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Html, }; var projectionProvider = GetProjectionProvider(projectionResult); var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(MockBehavior.Strict).Object; Mock.Get(documentMappingProvider).Setup(p => p.MapToDocumentRangesAsync(RazorLanguageKind.Html, Uri, It.IsAny <Range[]>(), CancellationToken.None)) .Returns(Task.FromResult <RazorMapToDocumentRangesResponse>(null)); var onTypeRenameHandler = new OnTypeRenameHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); var onTypeRenameRequest = new DocumentOnTypeRenameParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await onTypeRenameHandler.HandleRequestAsync(onTypeRenameRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(invokerCalled); Assert.Null(result); }
public async Task HandleRequestAsync_HtmlProjection_RemapsHighlightRange() { // Arrange var invokerCalled = false; var expectedResponse = GetMatchingHTMLBracketRange(5); var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(d => d.Version == 0, MockBehavior.Strict)); var htmlResponse = GetMatchingHTMLBracketRange(10); var requestInvoker = GetRequestInvoker <DocumentOnTypeRenameParams, DocumentOnTypeRenameResponseItem>( htmlResponse, (method, serverContentType, highlightParams, ct) => { Assert.Equal(MSLSPMethods.OnTypeRenameName, method); Assert.Equal(RazorLSPConstants.HtmlLSPContentTypeName, serverContentType); invokerCalled = true; }); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Html, }; var projectionProvider = GetProjectionProvider(projectionResult); var documentMappingProvider = GetDocumentMappingProvider(expectedResponse.Ranges, 0, RazorLanguageKind.Html); var onTypeRenameHandler = new OnTypeRenameHandler(documentManager, requestInvoker, projectionProvider, documentMappingProvider, LoggerProvider); var onTypeRenameRequest = new DocumentOnTypeRenameParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await onTypeRenameHandler.HandleRequestAsync(onTypeRenameRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(invokerCalled); Assert.NotNull(result); Assert.Collection(result.Ranges, r => Assert.Equal(expectedResponse.Ranges[0], r), r => Assert.Equal(expectedResponse.Ranges[1], r)); }
public async Task HandleRequestAsync_CSharpProjection_RemapsHighlightRange() { // Arrange var called = false; var expectedHighlight = GetHighlight(5, 5, 5, 5); var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(d => d.Version == 0)); var csharpHighlight = GetHighlight(100, 100, 100, 100); var requestInvoker = GetRequestInvoker <DocumentHighlightParams, DocumentHighlight[]>( new[] { csharpHighlight }, (method, serverKind, highlightParams, ct) => { Assert.Equal(Methods.TextDocumentDocumentHighlightName, method); Assert.Equal(LanguageServerKind.CSharp, serverKind); called = true; }); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp, }; var projectionProvider = GetProjectionProvider(projectionResult); var documentMappingProvider = GetDocumentMappingProvider(expectedHighlight.Range, 0, RazorLanguageKind.CSharp); var highlightHandler = new DocumentHighlightHandler(requestInvoker, documentManager, projectionProvider, documentMappingProvider); var highlightRequest = new DocumentHighlightParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await highlightHandler.HandleRequestAsync(highlightRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(called); var actualHighlight = Assert.Single(result); Assert.Equal(expectedHighlight.Range, actualHighlight.Range); }
public async Task TryGetProvisionalCompletionsAsync_ProjectionAtStartOfLine_ReturnsFalse() { // Arrange var completionRequest = new CompletionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Context = new CompletionContext() { TriggerKind = CompletionTriggerKind.TriggerCharacter, TriggerCharacter = "." }, Position = new Position(0, 1) }; var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>()); var requestInvoker = new Mock <LSPRequestInvoker>(); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Html, Position = new Position(1, 0) }; var previousCharacterProjection = 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(previousCharacterProjection)); var completionHandler = new CompletionHandler(JoinableTaskContext, requestInvoker.Object, documentManager, projectionProvider.Object); // Act var(succeeded, result) = await completionHandler.TryGetProvisionalCompletionsAsync(completionRequest, Mock.Of <LSPDocumentSnapshot>(), projectionResult, CancellationToken.None).ConfigureAwait(false); // Assert Assert.False(succeeded); Assert.Null(result); }
public async Task HandleRequestAsync_ProgressListener_ReturnsNull() { // Arrange var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>()); var requestInvoker = Mock.Of <LSPRequestInvoker>(); 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)); Task onCompleted = null; var documentMappingProvider = Mock.Of <LSPDocumentMappingProvider>(); var progressListener = Mock.Of <LSPProgressListener>(l => l.TryListenForProgress( It.IsAny <string>(), It.IsAny <Func <JToken, CancellationToken, Task> >(), It.IsAny <TimeSpan>(), It.IsAny <CancellationToken>(), out onCompleted) == false); var referencesHandler = new FindAllReferencesHandler(requestInvoker, documentManager, projectionProvider.Object, documentMappingProvider, progressListener); referencesHandler.WaitForProgressNotificationTimeout = TestWaitForProgressNotificationTimeout; var referenceRequest = new ReferenceParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(0, 1) }; // Act var result = await referencesHandler.HandleRequestAsync(referenceRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.Null(result); }
public async Task HandleRequestAsync_VersionMismatch_DiscardsLocation() { // Arrange var called = false; var expectedHighlight = GetHighlight(5, 5, 5, 5); var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(d => d.Version == 1)); var csharpHighlight = GetHighlight(100, 100, 100, 100); var requestInvoker = GetRequestInvoker <DocumentHighlightParams, DocumentHighlight[]>( new[] { csharpHighlight }, (method, serverContentType, highlightParams, ct) => { Assert.Equal(Methods.TextDocumentDocumentHighlightName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp, }; var projectionProvider = GetProjectionProvider(projectionResult); var documentMappingProvider = GetDocumentMappingProvider(expectedHighlight.Range, 0 /* Different from document version (1) */, RazorLanguageKind.CSharp); var highlightHandler = new DocumentHighlightHandler(requestInvoker, documentManager, projectionProvider, documentMappingProvider); var highlightRequest = new DocumentHighlightParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await highlightHandler.HandleRequestAsync(highlightRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(called); Assert.Empty(result); }
public async Task HandleRequestAsync_HtmlProjection_RemapsHighlightRange() { // Arrange var called = false; var expectedHighlight = GetHighlight(5, 5, 5, 5); var htmlHighlight = GetHighlight(100, 100, 100, 100); var requestInvoker = GetRequestInvoker <DocumentHighlightParams, DocumentHighlight[]>( new[] { htmlHighlight }, (textBuffer, method, clientName, highlightParams, ct) => { Assert.Equal(Methods.TextDocumentDocumentHighlightName, method); Assert.Equal(RazorLSPConstants.HtmlLanguageServerName, clientName); called = true; }); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Html, }; var projectionProvider = GetProjectionProvider(projectionResult); var documentMappingProvider = GetDocumentMappingProvider(expectedHighlight.Range, 0, RazorLanguageKind.Html); var highlightHandler = new DocumentHighlightHandler(requestInvoker, DocumentManager, projectionProvider, documentMappingProvider, LoggerProvider); var highlightRequest = new DocumentHighlightParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await highlightHandler.HandleRequestAsync(highlightRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(called); var actualHighlight = Assert.Single(result); Assert.Equal(expectedHighlight.Range, actualHighlight.Range); }
public async Task HandleRequestAsync_CSharpProjection_IncompatibleTriggerCharacter_ReturnsNull() { // Arrange var completionRequest = new CompletionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Context = new CompletionContext() { TriggerKind = CompletionTriggerKind.TriggerCharacter, TriggerCharacter = "<" }, Position = new Position(0, 1) }; var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>()); var requestInvoker = new Mock <LSPRequestInvoker>(); 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 completionHandler = new CompletionHandler(JoinableTaskContext, requestInvoker.Object, documentManager, projectionProvider.Object); // Act var result = await completionHandler.HandleRequestAsync(completionRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.Null(result); }
public async Task HandleRequestAsync_HtmlProjection_ReturnsNull() { // Arrange var documentManager = new TestDocumentManager(); var snapshot = new StringTextSnapshot(@" @code { public string _foo; }"); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(m => m.Snapshot == snapshot, MockBehavior.Strict)); var requestInvoker = Mock.Of <LSPRequestInvoker>(MockBehavior.Strict); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Html, }; var projectionProvider = new Mock <LSPProjectionProvider>(MockBehavior.Strict); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var mappingProvider = Mock.Of <LSPDocumentMappingProvider>(MockBehavior.Strict); var formatOnTypeHandler = new OnTypeFormattingHandler(documentManager, requestInvoker, projectionProvider.Object, mappingProvider); var formattingRequest = new DocumentOnTypeFormattingParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(0, 1), Character = ";", Options = new FormattingOptions() }; // Act var result = await formatOnTypeHandler.HandleRequestAsync(formattingRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.Null(result); }
public async Task HandleRequestAsync_ReturnNullIfCSharpLanguageServerReturnsNull() { // Arrange var virtualCSharpUri = new Uri("C:/path/to/file.razor.g.cs"); var requestInvoker = Mock.Of <LSPRequestInvoker>(i => i.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, SignatureHelp>( It.IsAny <ITextBuffer>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <TextDocumentPositionParams>(), It.IsAny <CancellationToken>()) == Task.FromResult(new ReinvocationResponse <SignatureHelp>("LanguageClient", null)), MockBehavior.Strict); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp, }; var projectionProvider = new Mock <LSPProjectionProvider>(MockBehavior.Strict); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var signatureHelpHandler = new SignatureHelpHandler(requestInvoker, DocumentManager, projectionProvider.Object, LoggerProvider); var signatureHelpRequest = new TextDocumentPositionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await signatureHelpHandler.HandleRequestAsync(signatureHelpRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.Null(result); }
public async Task TryGetProvisionalCompletionsAsync_AtCorrectProvisionalCompletionPoint_ReturnsExpectedResult() { // Arrange var completionRequest = new CompletionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Context = new CompletionContext() { TriggerKind = CompletionTriggerKind.TriggerCharacter, TriggerCharacter = "." }, Position = new Position(0, 1) }; var virtualDocumentUri = new Uri("C:/path/to/file.razor__virtual.cs"); var documentManager = new TestDocumentManager(); var languageServerCalled = false; var expectedItem = new CompletionItem() { InsertText = "DateTime" }; var requestInvoker = new Mock <LSPRequestInvoker>(MockBehavior.Strict); requestInvoker .Setup(r => r.RequestServerAsync <CompletionParams, SumType <CompletionItem[], CompletionList>?>(It.IsAny <string>(), LanguageServerKind.CSharp, It.IsAny <CompletionParams>(), It.IsAny <CancellationToken>())) .Callback <string, LanguageServerKind, CompletionParams, CancellationToken>((method, serverKind, completionParams, ct) => { Assert.Equal(Methods.TextDocumentCompletionName, method); Assert.Equal(LanguageServerKind.CSharp, serverKind); languageServerCalled = true; }) .Returns(Task.FromResult <SumType <CompletionItem[], CompletionList>?>(new[] { expectedItem })); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Html, Position = new Position(1, 7) }; var previousCharacterProjection = new ProjectionResult() { LanguageKind = RazorLanguageKind.CSharp, Position = new Position(100, 10), PositionIndex = 1000, Uri = virtualDocumentUri }; var projectionProvider = new Mock <LSPProjectionProvider>(); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(previousCharacterProjection)); var completionHandler = new CompletionHandler(JoinableTaskContext, requestInvoker.Object, documentManager, projectionProvider.Object); // Act var(succeeded, result) = await completionHandler.TryGetProvisionalCompletionsAsync(completionRequest, Mock.Of <LSPDocumentSnapshot>(), projectionResult, CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(succeeded); Assert.True(languageServerCalled); Assert.Equal(2, documentManager.UpdateVirtualDocumentCallCount); Assert.NotNull(result); var item = Assert.Single((CompletionItem[])result.Value); Assert.Equal(expectedItem.InsertText, item.InsertText); }
public async Task HandleRequestAsync_CSharpProjection_ReturnsKeywordsFromCSharp() { // Arrange var called = false; var expectedItems = new CompletionItem[] { new CompletionItem() { InsertText = "DateTime", Label = "DateTime" }, new CompletionItem() { InsertText = "FROMCSHARP", Label = "for" }, }; var completionRequest = new CompletionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Context = new CompletionContext() { TriggerKind = CompletionTriggerKind.Invoked, TriggerCharacter = "@" }, 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 <CompletionParams, SumType <CompletionItem[], CompletionList>?>(It.IsAny <string>(), It.IsAny <string>(), It.IsAny <CompletionParams>(), It.IsAny <CancellationToken>())) .Callback <string, string, CompletionParams, CancellationToken>((method, serverContentType, completionParams, ct) => { Assert.Equal(Methods.TextDocumentCompletionName, method); Assert.Equal(RazorLSPConstants.CSharpContentTypeName, serverContentType); called = true; }) .Returns(Task.FromResult <SumType <CompletionItem[], CompletionList>?>(expectedItems)); 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 completionHandler = new CompletionHandler(JoinableTaskContext, requestInvoker.Object, documentManager, projectionProvider.Object); // Act var result = await completionHandler.HandleRequestAsync(completionRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(called); Assert.True(result.HasValue); var _ = result.Value.Match <SumType <CompletionItem[], CompletionList> >( array => { Assert.Collection(array, item => Assert.Equal("DateTime", item.InsertText), item => { Assert.Equal("for", item.Label); Assert.Equal("FROMCSHARP", item.InsertText); }, item => Assert.Equal("foreach", item.Label), item => Assert.Equal("while", item.Label), item => Assert.Equal("switch", item.Label), item => Assert.Equal("lock", item.Label), item => Assert.Equal("case", item.Label), item => Assert.Equal("if", item.Label), item => Assert.Equal("try", item.Label), item => Assert.Equal("do", item.Label), item => Assert.Equal("using", item.Label) );; return(array); }, list => { throw new NotImplementedException(); }); }
public async Task HandleRequestAsync_InvokesCSharpServer_RemapsEdits() { // Arrange var invokedServer = false; var mappedTextEdits = false; var requestInvoker = new Mock <LSPRequestInvoker>(MockBehavior.Strict); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <VSInternalDocumentOnAutoInsertParams, VSInternalDocumentOnAutoInsertResponseItem>( It.IsAny <ITextBuffer>(), VSInternalMethods.OnAutoInsertName, It.IsAny <string>(), It.IsAny <VSInternalDocumentOnAutoInsertParams>(), It.IsAny <CancellationToken>())) .Callback <ITextBuffer, string, string, VSInternalDocumentOnAutoInsertParams, CancellationToken>((textBuffer, method, clientName, formattingParams, ct) => invokedServer = true) .Returns(Task.FromResult(new ReinvocationResponse <VSInternalDocumentOnAutoInsertResponseItem>("LanguageClientName", new VSInternalDocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() { Range = new Range(), NewText = "sometext" }, TextEditFormat = InsertTextFormat.Snippet }))); var projectionUri = new Uri(Uri.AbsoluteUri + "__virtual.html"); var projectionResult = new ProjectionResult() { Uri = projectionUri, LanguageKind = RazorLanguageKind.CSharp, }; var projectionProvider = new Mock <LSPProjectionProvider>(MockBehavior.Strict); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(MockBehavior.Strict); documentMappingProvider .Setup(d => d.RemapFormattedTextEditsAsync(projectionUri, It.IsAny <TextEdit[]>(), It.IsAny <FormattingOptions>(), /*containsSnippet*/ true, It.IsAny <CancellationToken>())) .Callback(() => mappedTextEdits = true) .Returns(Task.FromResult(new[] { new TextEdit() { NewText = "mapped-sometext" } })); var handler = new OnAutoInsertHandler(DocumentManager, requestInvoker.Object, projectionProvider.Object, documentMappingProvider.Object, LoggerProvider); var request = new VSInternalDocumentOnAutoInsertParams() { Character = "/", TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Options = new FormattingOptions() { OtherOptions = new Dictionary <string, object>() }, Position = new Position(1, 4) }; // Act var response = await handler.HandleRequestAsync(request, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(invokedServer); Assert.True(mappedTextEdits); Assert.NotNull(response); }
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); }
internal async Task <(bool, SumType <CompletionItem[], CompletionList>?)> TryGetProvisionalCompletionsAsync(CompletionParams request, LSPDocumentSnapshot documentSnapshot, ProjectionResult projection, CancellationToken cancellationToken) { SumType <CompletionItem[], CompletionList>?result = null; if (projection.LanguageKind != RazorLanguageKind.Html || request.Context.TriggerKind != CompletionTriggerKind.TriggerCharacter || request.Context.TriggerCharacter != ".") { return(false, result); } if (projection.Position.Character == 0) { // We're at the start of line. Can't have provisional completions here. return(false, result); } var previousCharacterPosition = new Position(projection.Position.Line, projection.Position.Character - 1); var previousCharacterProjection = await _projectionProvider.GetProjectionAsync(documentSnapshot, previousCharacterPosition, cancellationToken).ConfigureAwait(false); if (previousCharacterProjection == null || previousCharacterProjection.LanguageKind != RazorLanguageKind.CSharp) { return(false, result); } if (!(_documentManager is TrackingLSPDocumentManager trackingDocumentManager)) { return(false, result); } // Edit the CSharp projected document to contain a '.'. This allows C# completion to provide valid // completion items for moments when a user has typed a '.' that's typically interpreted as Html. var addProvisionalDot = new VisualStudioTextChange(previousCharacterProjection.PositionIndex, 0, "."); await _joinableTaskFactory.SwitchToMainThreadAsync(); trackingDocumentManager.UpdateVirtualDocument <CSharpVirtualDocument>(documentSnapshot.Uri, new[] { addProvisionalDot }, previousCharacterProjection.HostDocumentVersion); var provisionalCompletionParams = new CompletionParams() { Context = request.Context, Position = new Position(previousCharacterProjection.Position.Line, previousCharacterProjection.Position.Character + 1), TextDocument = new TextDocumentIdentifier() { Uri = previousCharacterProjection.Uri } }; result = await _requestInvoker.ReinvokeRequestOnServerAsync <CompletionParams, SumType <CompletionItem[], CompletionList>?>( Methods.TextDocumentCompletionName, RazorLSPConstants.CSharpContentTypeName, provisionalCompletionParams, cancellationToken).ConfigureAwait(true); // We have now obtained the necessary completion items. We no longer need the provisional change. Revert. var removeProvisionalDot = new VisualStudioTextChange(previousCharacterProjection.PositionIndex, 1, string.Empty); trackingDocumentManager.UpdateVirtualDocument <CSharpVirtualDocument>(documentSnapshot.Uri, new[] { removeProvisionalDot }, previousCharacterProjection.HostDocumentVersion); return(true, result); }
public async Task HandleRequestAsync_HtmlProjection_InvokesHtmlLanguageServer() { // Arrange var invokedLSPRequest = false; var invokedRemapRequest = false; var expectedLocation = GetLocation(5, 5, 5, 5, Uri); var virtualHtmlUri = new Uri("C:/path/to/file.razor__virtual.html"); var htmlLocation = GetLocation(100, 100, 100, 100, virtualHtmlUri); var requestInvoker = new Mock <LSPRequestInvoker>(MockBehavior.Strict); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <TextDocumentPositionParams, Location[]>( It.IsAny <ITextBuffer>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <TextDocumentPositionParams>(), It.IsAny <CancellationToken>())) .Callback <ITextBuffer, string, string, TextDocumentPositionParams, CancellationToken>((textBuffer, method, clientName, definitionParams, ct) => { Assert.Equal(Methods.TextDocumentDefinitionName, method); Assert.Equal(RazorLSPConstants.HtmlLanguageServerName, clientName); invokedLSPRequest = true; }) .Returns(Task.FromResult(new ReinvocationResponse <Location[]>("LanguageClientName", new[] { htmlLocation }))); var projectionResult = new ProjectionResult() { LanguageKind = RazorLanguageKind.Html, }; var projectionProvider = new Mock <LSPProjectionProvider>(MockBehavior.Strict); projectionProvider.Setup(p => p.GetProjectionAsync(It.IsAny <LSPDocumentSnapshot>(), It.IsAny <Position>(), It.IsAny <CancellationToken>())).Returns(Task.FromResult(projectionResult)); var documentMappingProvider = new Mock <LSPDocumentMappingProvider>(MockBehavior.Strict); documentMappingProvider .Setup(d => d.RemapLocationsAsync(It.IsAny <Location[]>(), It.IsAny <CancellationToken>())) .Callback <Location[], CancellationToken>((locations, token) => { Assert.Equal(htmlLocation, locations[0]); invokedRemapRequest = true; }) .Returns(Task.FromResult(Array.Empty <Location>())); var definitionHandler = new GoToDefinitionHandler(requestInvoker.Object, DocumentManager, projectionProvider.Object, documentMappingProvider.Object, LoggerProvider); var definitionRequest = new TextDocumentPositionParams() { TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Position = new Position(10, 5) }; // Act var result = await definitionHandler.HandleRequestAsync(definitionRequest, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(invokedLSPRequest); Assert.True(invokedRemapRequest); // Actual remapping behavior is tested elsewhere. }
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); }
public async Task HandleRequestAsync_InvokesServer_RemapsEdits() { // Arrange var documentManager = new TestDocumentManager(); documentManager.AddDocument(Uri, Mock.Of <LSPDocumentSnapshot>(s => s.Uri == Uri && s.Snapshot == Mock.Of <ITextSnapshot>())); var invokedServer = false; var mappedTextEdits = false; var requestInvoker = new Mock <LSPRequestInvoker>(MockBehavior.Strict); requestInvoker .Setup(r => r.ReinvokeRequestOnServerAsync <DocumentOnAutoInsertParams, DocumentOnAutoInsertResponseItem>(MSLSPMethods.OnAutoInsertName, It.IsAny <LanguageServerKind>(), It.IsAny <DocumentOnAutoInsertParams>(), It.IsAny <CancellationToken>())) .Callback <string, LanguageServerKind, DocumentOnAutoInsertParams, CancellationToken>((method, serverKind, formattingParams, ct) => { invokedServer = true; }) .Returns(Task.FromResult(new DocumentOnAutoInsertResponseItem() { TextEdit = new TextEdit() { Range = new Range(), NewText = "sometext" } })); var projectionUri = new Uri(Uri.AbsoluteUri + "__virtual.html"); var projectionResult = new ProjectionResult() { Uri = projectionUri, 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 documentMappingProvider = new Mock <LSPDocumentMappingProvider>(MockBehavior.Strict); documentMappingProvider .Setup(d => d.RemapTextEditsAsync(projectionUri, It.IsAny <TextEdit[]>(), It.IsAny <CancellationToken>())) .Callback(() => { mappedTextEdits = true; }) .Returns(Task.FromResult(new[] { new TextEdit() })); var handler = new OnAutoInsertHandler(documentManager, requestInvoker.Object, projectionProvider.Object, documentMappingProvider.Object); var request = new DocumentOnAutoInsertParams() { Character = "=", TextDocument = new TextDocumentIdentifier() { Uri = Uri }, Options = new FormattingOptions() { OtherOptions = new Dictionary <string, object>() }, Position = new Position(1, 4) }; // Act var response = await handler.HandleRequestAsync(request, new ClientCapabilities(), CancellationToken.None).ConfigureAwait(false); // Assert Assert.True(invokedServer); Assert.True(mappedTextEdits); Assert.NotNull(response); }
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); }
private async Task <ProjectionResult?> GetProjectionCoreAsync(LSPDocumentSnapshot documentSnapshot, Position position, bool rejectOnNewerParallelRequest, CancellationToken cancellationToken) { if (documentSnapshot is null) { throw new ArgumentNullException(nameof(documentSnapshot)); } if (position is null) { throw new ArgumentNullException(nameof(position)); } // We initialize the logger here instead of the constructor as the projection provider is constructed // *before* the language server. Thus, the log hub has yet to be initialized, thus we would be unable to // create the logger at that time. await InitializeLogHubAsync(cancellationToken).ConfigureAwait(false); var languageQueryParams = new RazorLanguageQueryParams() { Position = position, Uri = documentSnapshot.Uri }; var response = await _requestInvoker.ReinvokeRequestOnServerAsync <RazorLanguageQueryParams, RazorLanguageQueryResponse>( documentSnapshot.Snapshot.TextBuffer, LanguageServerConstants.RazorLanguageQueryEndpoint, RazorLSPConstants.RazorLanguageServerName, CheckRazorLanguageQueryCapability, languageQueryParams, cancellationToken).ConfigureAwait(false); var languageResponse = response?.Response; if (languageResponse is null) { _logHubLogger?.LogInformation("The language server is still being spun up. Could not resolve the projection."); return(null); } VirtualDocumentSnapshot virtualDocument; if (languageResponse.Kind == RazorLanguageKind.CSharp && documentSnapshot.TryGetVirtualDocument <CSharpVirtualDocumentSnapshot>(out var csharpDoc)) { virtualDocument = csharpDoc; } else if (languageResponse.Kind == RazorLanguageKind.Html && documentSnapshot.TryGetVirtualDocument <HtmlVirtualDocumentSnapshot>(out var htmlDoc)) { virtualDocument = htmlDoc; } else { _logHubLogger?.LogInformation($"Could not find projection for {languageResponse.Kind:G}."); return(null); } if (languageResponse.HostDocumentVersion is null) { // There should always be a document version attached to an open document. // Log it and move on as if it was synchronized. var message = $"Could not find a document version associated with the document '{documentSnapshot.Uri}'"; _activityLogger.LogVerbose(message); _logHubLogger?.LogWarning(message); } else { var synchronized = await _documentSynchronizer.TrySynchronizeVirtualDocumentAsync(documentSnapshot.Version, virtualDocument, rejectOnNewerParallelRequest, cancellationToken).ConfigureAwait(false); if (!synchronized) { _logHubLogger?.LogInformation("Could not synchronize."); return(null); } } var result = new ProjectionResult() { Uri = virtualDocument.Uri, Position = languageResponse.Position, PositionIndex = languageResponse.PositionIndex, LanguageKind = languageResponse.Kind, HostDocumentVersion = languageResponse.HostDocumentVersion }; return(result); }
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_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); }