public static async Task <ILanguageClient> StartServerWithTextAsync(TestContext testContext, string text, DocumentUri documentUri, Action <LanguageClientOptions>?onClientOptions = null, IResourceTypeProvider?resourceTypeProvider = null, IFileResolver?fileResolver = null) { var diagnosticsPublished = new TaskCompletionSource <PublishDiagnosticsParams>(); fileResolver ??= new InMemoryFileResolver(new Dictionary <Uri, string> { [documentUri.ToUri()] = text, }); var client = await IntegrationTestHelper.StartServerWithClientConnectionAsync( testContext, options => { onClientOptions?.Invoke(options); options.OnPublishDiagnostics(p => { testContext.WriteLine($"Received {p.Diagnostics.Count()} diagnostic(s)."); diagnosticsPublished.SetResult(p); }); }, resourceTypeProvider : resourceTypeProvider, fileResolver : fileResolver); // send open document notification client.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(documentUri, text, 0)); testContext.WriteLine($"Opened file {documentUri}."); // notifications don't produce responses, // but our server should send us diagnostics when it receives the notification await IntegrationTestHelper.WithTimeoutAsync(diagnosticsPublished.Task); return(client); }
public async Task VerifyDisableNextLineCodeActionInvocationFiresTelemetryEvent() { var bicepFileContents = @"param storageAccount string = 'testStorageAccount'"; var bicepFilePath = FileHelper.SaveResultFile(TestContext, "main.bicep", bicepFileContents); var documentUri = DocumentUri.FromFileSystemPath(bicepFilePath); var uri = documentUri.ToUri(); var files = new Dictionary <Uri, string> { [uri] = bicepFileContents, }; var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateForFiles(files, uri, BicepTestConstants.FileResolver, BicepTestConstants.BuiltInConfiguration), BicepTestConstants.BuiltInConfiguration); var diagnostics = compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); var telemetryReceived = new TaskCompletionSource <BicepTelemetryEvent>(); using var helper = await LanguageServerHelper.StartServerWithClientConnectionAsync( TestContext, options => { options.OnTelemetryEvent <BicepTelemetryEvent>(telemetry => telemetryReceived.SetResult(telemetry)); }, new Server.CreationOptions(NamespaceProvider: BicepTestConstants.NamespaceProvider, FileResolver: new InMemoryFileResolver(files))); var client = helper.Client; client.TextDocument.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(documentUri, files[uri], 1)); var lineStarts = compilation.SourceFileGrouping.EntryPoint.LineStarts; var codeActions = await client.RequestCodeAction(new CodeActionParams { TextDocument = new TextDocumentIdentifier(documentUri), Range = diagnostics.First().ToRange(lineStarts) }); var disableNextLineCodeAction = codeActions.First(x => x.CodeAction !.Title == "Disable no-unused-params").CodeAction; _ = await client !.ResolveCodeAction(disableNextLineCodeAction !); Command?command = disableNextLineCodeAction !.Command; JArray? arguments = command !.Arguments; await client.Workspace.ExecuteCommand(command); var bicepTelemetryEvent = await IntegrationTestHelper.WithTimeoutAsync(telemetryReceived.Task); IDictionary <string, string> properties = new Dictionary <string, string> { { "code", "no-unused-params" } }; bicepTelemetryEvent.EventName.Should().Be(TelemetryConstants.EventNames.DisableNextLineDiagnostics); bicepTelemetryEvent.Properties.Should().Equal(properties); }
public async Task OpenFileOnceAsync(TestContext testContext, string text, DocumentUri documentUri) { var completionSource = new TaskCompletionSource <PublishDiagnosticsParams>(); // this is why this method is called *Once this.notificationRouter.TryAdd(documentUri, completionSource).Should().BeTrue("because nothing should have registered a completion source for this test before it ran"); // send the notification this.Client.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(documentUri, text, 0)); testContext.WriteLine($"Opened file {documentUri}."); // notifications don't produce responses, // but our server should send us diagnostics when it receives the notification await IntegrationTestHelper.WithTimeoutAsync(completionSource.Task); }
public async Task <T> WaitNext(int timeout = 10000) { Task <T> onMessageTask; lock (lockObj) { while (listenPosition >= completionSources.Count) { completionSources.Add(new TaskCompletionSource <T>()); } onMessageTask = completionSources[listenPosition].Task; listenPosition++; } return(await IntegrationTestHelper.WithTimeoutAsync(onMessageTask, timeout)); }
public static async Task <ILanguageClient> StartServerWithTextAsync(string text, DocumentUri uri, Action <LanguageClientOptions>?onClientOptions = null, Func <IResourceTypeProvider>?typeProviderBuilder = null) { var diagnosticsPublished = new TaskCompletionSource <PublishDiagnosticsParams>(); var client = await IntegrationTestHelper.StartServerWithClientConnectionAsync(options => { onClientOptions?.Invoke(options); options.OnPublishDiagnostics(p => diagnosticsPublished.SetResult(p)); }, typeProviderBuilder); // send open document notification client.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(uri, text, 0)); // notifications don't produce responses, // but our server should send us diagnostics when it receives the notification await IntegrationTestHelper.WithTimeoutAsync(diagnosticsPublished.Task); return(client); }
private async Task <BicepTelemetryEvent> ResolveCompletionAsync(string text, string prefix, Position position) { var fileSystemDict = new Dictionary <Uri, string>(); var telemetryReceived = new TaskCompletionSource <BicepTelemetryEvent>(); using var helper = await LanguageServerHelper.StartServerWithClientConnectionAsync( TestContext, options => { options.OnTelemetryEvent <BicepTelemetryEvent>(telemetry => telemetryReceived.SetResult(telemetry)); }, new LanguageServer.Server.CreationOptions(NamespaceProvider: BicepTestConstants.NamespaceProvider, FileResolver: new InMemoryFileResolver(fileSystemDict))); var client = helper.Client; var mainUri = DocumentUri.FromFileSystemPath("/main.bicep"); fileSystemDict[mainUri.ToUri()] = text; client.TextDocument.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(mainUri, fileSystemDict[mainUri.ToUri()], 1)); var completions = await client.RequestCompletion(new CompletionParams { TextDocument = new TextDocumentIdentifier(mainUri), Position = position, }); CompletionItem completionItem = completions.Where(x => x.Kind == CompletionItemKind.Snippet && x.Label == prefix).First(); Command? command = completionItem.Command; JArray? arguments = command !.Arguments; BicepTelemetryEvent?telemetryEvent = arguments !.First().ToObject <BicepTelemetryEvent>(); await client.ResolveCompletion(completionItem); await client.Workspace.ExecuteCommand(command); return(await IntegrationTestHelper.WithTimeoutAsync(telemetryReceived.Task)); }
public static async Task <LanguageServerHelper> StartServerWithTextAsync(TestContext testContext, string text, DocumentUri documentUri, Action <LanguageClientOptions>?onClientOptions = null, Server.CreationOptions?creationOptions = null) { var diagnosticsPublished = new TaskCompletionSource <PublishDiagnosticsParams>(); creationOptions ??= new Server.CreationOptions(); creationOptions = creationOptions with { FileResolver = creationOptions.FileResolver ?? new InMemoryFileResolver(new Dictionary <Uri, string> { [documentUri.ToUri()] = text, }), ModuleRestoreScheduler = creationOptions.ModuleRestoreScheduler ?? BicepTestConstants.ModuleRestoreScheduler }; var helper = await LanguageServerHelper.StartServerWithClientConnectionAsync( testContext, options => { onClientOptions?.Invoke(options); options.OnPublishDiagnostics(p => { testContext.WriteLine($"Received {p.Diagnostics.Count()} diagnostic(s)."); diagnosticsPublished.SetResult(p); }); }, creationOptions); // send open document notification helper.Client.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(documentUri, text, 0)); testContext.WriteLine($"Opened file {documentUri}."); // notifications don't produce responses, // but our server should send us diagnostics when it receives the notification await IntegrationTestHelper.WithTimeoutAsync(diagnosticsPublished.Task); return(helper); }
public async Task DidOpenTextDocument_should_trigger_PublishDiagnostics() { var documentUri = DocumentUri.From("/template.bicep"); var diagsReceived = new TaskCompletionSource <PublishDiagnosticsParams>(); var client = await IntegrationTestHelper.StartServerWithClientConnectionAsync(options => { options.OnPublishDiagnostics(diags => { diagsReceived.SetResult(diags); }); }); // open document client.TextDocument.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(documentUri, @" param myParam string = 2 resource myRes 'invalidFormat' = { } randomToken ", 1)); var response = await IntegrationTestHelper.WithTimeoutAsync(diagsReceived.Task); response.Diagnostics.Should().SatisfyRespectively( d => { d.Range.Should().HaveRange((1, 23), (1, 24)); d.Should().HaveCodeAndSeverity("BCP027", DiagnosticSeverity.Error); }, d => { d.Range.Should().HaveRange((2, 15), (2, 30)); d.Should().HaveCodeAndSeverity("BCP029", DiagnosticSeverity.Error); }, d => { d.Range.Should().HaveRange((5, 0), (5, 11)); d.Should().HaveCodeAndSeverity("BCP007", DiagnosticSeverity.Error); } ); // change document diagsReceived = new TaskCompletionSource <PublishDiagnosticsParams>(); client.TextDocument.DidChangeTextDocument(TextDocumentParamHelper.CreateDidChangeTextDocumentParams(documentUri, @" param myParam string = 'fixed!' resource myRes 'invalidFormat' = { } randomToken ", 2)); response = await IntegrationTestHelper.WithTimeoutAsync(diagsReceived.Task); response.Diagnostics.Should().SatisfyRespectively( d => { d.Range.Should().HaveRange((2, 15), (2, 30)); d.Should().HaveCodeAndSeverity("BCP029", DiagnosticSeverity.Error); }, d => { d.Range.Should().HaveRange((5, 0), (5, 11)); d.Should().HaveCodeAndSeverity("BCP007", DiagnosticSeverity.Error); } ); // close document diagsReceived = new TaskCompletionSource <PublishDiagnosticsParams>(); client.TextDocument.DidCloseTextDocument(TextDocumentParamHelper.CreateDidCloseTextDocumentParams(documentUri, 3)); response = await IntegrationTestHelper.WithTimeoutAsync(diagsReceived.Task); response.Diagnostics.Should().BeEmpty(); }
public async Task DidOpenTextDocument_should_trigger_PublishDiagnostics() { var documentUri = DocumentUri.From("/template.bicep"); var diagsReceived = new TaskCompletionSource <PublishDiagnosticsParams>(); var client = await IntegrationTestHelper.StartServerWithClientConnectionAsync(this.TestContext, options => { options.OnPublishDiagnostics(diags => { diagsReceived.SetResult(diags); }); }); // open document client.TextDocument.DidOpenTextDocument(TextDocumentParamHelper.CreateDidOpenDocumentParams(documentUri, @" param myParam string = 2 resource myRes 'invalidFormat' = { } randomToken ", 1)); var response = await IntegrationTestHelper.WithTimeoutAsync(diagsReceived.Task); response.Diagnostics.Should().SatisfyRespectively( d => { d.Range.Should().HaveRange((1, 6), (1, 13)); // note documentation pretty printing moves Uri to code for output d.Should().HaveCodeAndSeverity(new NoUnusedParametersRule().Uri !.AbsoluteUri, DiagnosticSeverity.Warning); }, d => { d.Range.Should().HaveRange((1, 23), (1, 24)); d.Should().HaveCodeAndSeverity("BCP027", DiagnosticSeverity.Error); }, d => { d.Range.Should().HaveRange((2, 15), (2, 30)); d.Should().HaveCodeAndSeverity("BCP029", DiagnosticSeverity.Error); }, d => { d.Range.Should().HaveRange((5, 0), (5, 11)); d.Should().HaveCodeAndSeverity("BCP007", DiagnosticSeverity.Error); } ); // change document diagsReceived = new TaskCompletionSource <PublishDiagnosticsParams>(); client.TextDocument.DidChangeTextDocument(TextDocumentParamHelper.CreateDidChangeTextDocumentParams(documentUri, @" param myParam string = 'fixed!' resource myRes 'invalidFormat' = { } randomToken ", 2)); response = await IntegrationTestHelper.WithTimeoutAsync(diagsReceived.Task); response.Diagnostics.Should().SatisfyRespectively( d => { d.Range.Should().HaveRange((1, 6), (1, 13)); // documentation provided with linter sets code to uri for pretty link print outs d.Should().HaveCodeAndSeverity(new NoUnusedParametersRule().Uri !.AbsoluteUri, DiagnosticSeverity.Warning); }, d => { d.Range.Should().HaveRange((2, 15), (2, 30)); d.Should().HaveCodeAndSeverity("BCP029", DiagnosticSeverity.Error); }, d => { d.Range.Should().HaveRange((5, 0), (5, 11)); d.Should().HaveCodeAndSeverity("BCP007", DiagnosticSeverity.Error); } ); // close document diagsReceived = new TaskCompletionSource <PublishDiagnosticsParams>(); client.TextDocument.DidCloseTextDocument(TextDocumentParamHelper.CreateDidCloseTextDocumentParams(documentUri, 3)); response = await IntegrationTestHelper.WithTimeoutAsync(diagsReceived.Task); response.Diagnostics.Should().BeEmpty(); }