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);
        }
Exemple #2
0
        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);
        }
Exemple #6
0
        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();
        }