public void VerifySnippetTemplatesAreErrorFree(CompletionData completionData) { string pathPrefix = $"Completions/SnippetTemplates/{completionData.Prefix}"; var outputDirectory = FileHelper.SaveEmbeddedResourcesWithPathPrefix(TestContext, typeof(SnippetTemplatesTests).Assembly, pathPrefix); var mainUri = PathHelper.FilePathToFileUrl(Path.Combine(outputDirectory, "main.bicep")); var bicepContents = completionData.SnippetText; var files = new Dictionary <Uri, string> { [mainUri] = bicepContents, }; var prefix = completionData.Prefix; // Template - module.bicep requires a path. So we'll create param.bicep file and // specify it in module snippet template if (prefix == "module") { var paramUri = PathHelper.FilePathToFileUrl(Path.Combine(outputDirectory, "param.bicep")); files.Add(paramUri, "param myParam string = 'test'"); } var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver)); var semanticModel = compilation.GetEntrypointSemanticModel(); if (semanticModel.HasErrors()) { var errors = semanticModel.GetAllDiagnostics().Where(x => x.Level == DiagnosticLevel.Error); var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(bicepContents, "\n", errors, diag => OutputHelper.GetDiagLoggingString(bicepContents, outputDirectory, diag)); Assert.Fail("Template with prefix {0} contains errors. Please fix following errors:\n {1}", completionData.Prefix, sourceTextWithDiags); } }
public void ProgramsShouldProduceExpectedUserDeclaredSymbols(DataSet dataSet) { var compilation = dataSet.CopyFilesAndCreateCompilation(TestContext, out var outputDirectory); var model = compilation.GetEntrypointSemanticModel(); var symbols = SymbolCollector .CollectSymbols(model) .OfType <DeclaredSymbol>(); var lineStarts = compilation.SyntaxTreeGrouping.EntryPoint.LineStarts; string getLoggingString(DeclaredSymbol symbol) { (_, var startChar) = TextCoordinateConverter.GetPosition(lineStarts, symbol.DeclaringSyntax.Span.Position); return($"{symbol.Kind} {symbol.Name}. Type: {symbol.Type}. Declaration start char: {startChar}, length: {symbol.DeclaringSyntax.Span.Length}"); } var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(dataSet, symbols, symb => symb.NameSyntax.Span, getLoggingString); var resultsFile = Path.Combine(outputDirectory, DataSet.TestFileMainDiagnostics); File.WriteAllText(resultsFile, sourceTextWithDiags); sourceTextWithDiags.Should().EqualWithLineByLineDiffOutput( dataSet.Symbols, expectedLocation: OutputHelper.GetBaselineUpdatePath(dataSet, DataSet.TestFileMainSymbols), actualLocation: resultsFile); }
public void ProgramsShouldProduceExpectedUserDeclaredSymbols(DataSet dataSet) { var compilation = new Compilation(TestResourceTypeProvider.CreateRegistrar(), SyntaxFactory.CreateFromText(dataSet.Bicep)); var model = compilation.GetSemanticModel(); var symbols = SymbolCollector .CollectSymbols(model) .OfType <DeclaredSymbol>(); var lineStarts = TextCoordinateConverter.GetLineStarts(dataSet.Bicep); string getLoggingString(DeclaredSymbol symbol) { (_, var startChar) = TextCoordinateConverter.GetPosition(lineStarts, symbol.DeclaringSyntax.Span.Position); return($"{symbol.Kind} {symbol.Name}. Type: {symbol.Type}. Declaration start char: {startChar}, length: {symbol.DeclaringSyntax.Span.Length}"); } var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(dataSet, symbols, symb => symb.NameSyntax.Span, getLoggingString); var resultsFile = FileHelper.SaveResultFile(this.TestContext !, Path.Combine(dataSet.Name, DataSet.TestFileMainSymbols), sourceTextWithDiags); sourceTextWithDiags.Should().EqualWithLineByLineDiffOutput( dataSet.Symbols, expectedLocation: OutputHelper.GetBaselineUpdatePath(dataSet, DataSet.TestFileMainSymbols), actualLocation: resultsFile); }
public async Task ValidateSnippetCompletionAfterPlaceholderReplacements(CompletionData completionData) { string pathPrefix = $"Completions/SnippetTemplates/{completionData.Prefix}"; var outputDirectory = FileHelper.SaveEmbeddedResourcesWithPathPrefix(TestContext, typeof(CompletionTests).Assembly, pathPrefix); var bicepFileName = Path.Combine(outputDirectory, "main.bicep"); var bicepSourceFileName = Path.Combine("src", "Bicep.LangServer.IntegrationTests", pathPrefix, Path.GetRelativePath(outputDirectory, bicepFileName)); File.Exists(bicepFileName).Should().BeTrue($"Snippet placeholder file \"{bicepSourceFileName}\" should be checked in"); var bicepContents = await File.ReadAllTextAsync(bicepFileName); bicepContents = StringUtils.ReplaceNewlines(bicepContents, "\n"); var cursor = bicepContents.IndexOf("// Insert snippet here"); // Request the expected completion from the server, and ensure it is unique + valid var completionText = await RequestSnippetCompletion(bicepFileName, completionData, bicepContents, cursor); // Replace all the placeholders with values from the placeholder file var replacementContents = SnippetCompletionTestHelper.GetSnippetTextAfterPlaceholderReplacements(completionText, bicepContents); var bicepContentsReplaced = bicepContents.Substring(0, cursor) + replacementContents + bicepContents.Substring(cursor); using (new AssertionScope()) { var combinedFileName = Path.Combine(outputDirectory, "main.combined.bicep"); var combinedSourceFileName = Path.Combine("src", "Bicep.LangServer.IntegrationTests", pathPrefix, Path.GetRelativePath(outputDirectory, combinedFileName)); File.Exists(combinedFileName).Should().BeTrue($"Combined snippet file \"{combinedSourceFileName}\" should be checked in"); var combinedFileUri = PathHelper.FilePathToFileUrl(combinedFileName); var sourceFileGrouping = SourceFileGroupingFactory.CreateForFiles(new Dictionary <Uri, string> { [combinedFileUri] = bicepContentsReplaced, }, combinedFileUri, BicepTestConstants.FileResolver); var compilation = new Compilation(TypeProvider, sourceFileGrouping); var diagnostics = compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(bicepContentsReplaced, "\n", diagnostics, diag => OutputHelper.GetDiagLoggingString(bicepContentsReplaced, outputDirectory, diag)); File.WriteAllText(combinedFileName + ".actual", sourceTextWithDiags); if (diagnostics.Any()) { Execute.Assertion.FailWith( "Expected {0} file to not contain errors or warnings, but found {1}. Please fix errors/warnings mentioned in below section in {0} file:\n {2}", "main.combined.bicep", diagnostics.Count(), sourceTextWithDiags); } sourceTextWithDiags.Should().EqualWithLineByLineDiffOutput( TestContext, File.Exists(combinedFileName) ? (await File.ReadAllTextAsync(combinedFileName)) : string.Empty, expectedLocation: combinedSourceFileName, actualLocation: combinedFileName + ".actual"); } }
public void ProgramsShouldProduceExpectedDiagnostics(DataSet dataSet) { var compilation = new Compilation(TestResourceTypeProvider.CreateRegistrar(), SyntaxFactory.CreateFromText(dataSet.Bicep)); var model = compilation.GetSemanticModel(); string getLoggingString(Diagnostic diagnostic) { var spanText = OutputHelper.GetSpanText(dataSet.Bicep, diagnostic); return($"[{diagnostic.Code} ({diagnostic.Level})] {diagnostic.Message} |{spanText}|"); } var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(dataSet, model.GetAllDiagnostics(), getLoggingString); var resultsFile = FileHelper.SaveResultFile(this.TestContext !, Path.Combine(dataSet.Name, DataSet.TestFileMainDiagnostics), sourceTextWithDiags); sourceTextWithDiags.Should().EqualWithLineByLineDiffOutput( dataSet.Diagnostics, expectedLocation: OutputHelper.GetBaselineUpdatePath(dataSet, DataSet.TestFileMainDiagnostics), actualLocation: resultsFile); }
public async Task ValidateSnippetCompletionAfterPlaceholderReplacements(CompletionData completionData) { string pathPrefix = $"Completions/SnippetTemplates/{completionData.Prefix}"; var outputDirectory = FileHelper.SaveEmbeddedResourcesWithPathPrefix(TestContext, typeof(CompletionTests).Assembly, pathPrefix); var bicepFileName = Path.Combine(outputDirectory, "main.bicep"); var bicepSourceFileName = Path.Combine("src", "Bicep.LangServer.IntegrationTests", pathPrefix, Path.GetRelativePath(outputDirectory, bicepFileName)); File.Exists(bicepFileName).Should().BeTrue($"Snippet placeholder file \"{bicepSourceFileName}\" should be checked in"); var bicepContents = await File.ReadAllTextAsync(bicepFileName); // Request the expected completion from the server, and ensure it is unique + valid var completionText = await RequestSnippetCompletion(bicepFileName, completionData, bicepContents); // Replace all the placeholders with values from the placeholder file var replacementContents = SnippetCompletionTestHelper.GetSnippetTextAfterPlaceholderReplacements(completionText, bicepContents); using (new AssertionScope()) { var combinedFileName = Path.Combine(outputDirectory, "main.combined.bicep"); var combinedSourceFileName = Path.Combine("src", "Bicep.LangServer.IntegrationTests", pathPrefix, Path.GetRelativePath(outputDirectory, combinedFileName)); File.Exists(combinedFileName).Should().BeTrue($"Combined snippet file \"{combinedSourceFileName}\" should be checked in"); var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), new Workspace(), PathHelper.FilePathToFileUrl(combinedFileName)); var compilation = new Compilation(TypeProvider, syntaxTreeGrouping); var diagnostics = compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(replacementContents, Environment.NewLine, diagnostics, diag => OutputHelper.GetDiagLoggingString(replacementContents, outputDirectory, diag)); File.WriteAllText(combinedFileName + ".actual", sourceTextWithDiags); sourceTextWithDiags.Should().EqualWithLineByLineDiffOutput( TestContext, File.Exists(combinedFileName) ? (await File.ReadAllTextAsync(combinedFileName)) : string.Empty, expectedLocation: combinedSourceFileName, actualLocation: combinedFileName + ".actual"); } }
public void ProgramsShouldProduceExpectedDiagnostics(DataSet dataSet) { var compilation = dataSet.CopyFilesAndCreateCompilation(TestContext, out var outputDirectory); var model = compilation.GetEntrypointSemanticModel(); string getLoggingString(Diagnostic diagnostic) { var spanText = OutputHelper.GetSpanText(dataSet.Bicep, diagnostic); var message = diagnostic.Message.Replace($"{outputDirectory}{Path.DirectorySeparatorChar}", "${TEST_OUTPUT_DIR}"); return($"[{diagnostic.Code} ({diagnostic.Level})] {message} |{spanText}|"); } var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(dataSet, model.GetAllDiagnostics(), getLoggingString); var resultsFile = Path.Combine(outputDirectory, DataSet.TestFileMainDiagnostics); File.WriteAllText(resultsFile, sourceTextWithDiags); sourceTextWithDiags.Should().EqualWithLineByLineDiffOutput( dataSet.Diagnostics, expectedLocation: OutputHelper.GetBaselineUpdatePath(dataSet, DataSet.TestFileMainDiagnostics), actualLocation: resultsFile); }
public void VerifySnippetTemplatesAreErrorFree(CompletionData completionData) { string pathPrefix = $"Completions/SnippetTemplates/{completionData.Prefix}"; var outputDirectory = FileHelper.SaveEmbeddedResourcesWithPathPrefix(TestContext, typeof(SnippetTemplatesTests).Assembly, pathPrefix); var mainUri = PathHelper.FilePathToFileUrl(Path.Combine(outputDirectory, "main.bicep")); var bicepContents = completionData.SnippetText; var files = new Dictionary <Uri, string> { [mainUri] = bicepContents, }; // overrides for certain snippets which have contextual dependencies (e.g. external files) switch (completionData.Prefix) { case "module": var paramUri = PathHelper.FilePathToFileUrl(Path.Combine(outputDirectory, "param.bicep")); files.Add(paramUri, "param myParam string = 'test'"); break; case "res-logic-app-from-file": var requiredFile = PathHelper.FilePathToFileUrl(Path.Combine(outputDirectory, "REQUIRED")); files.Add(requiredFile, @"{""definition"":{""$schema"":""https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#"",""contentVersion"":""1.0.0.0"",""outputs"":{}}}"); return; } var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver, BicepTestConstants.BuiltInConfiguration), BicepTestConstants.BuiltInConfiguration); var semanticModel = compilation.GetEntrypointSemanticModel(); if (semanticModel.HasErrors()) { var errors = semanticModel.GetAllDiagnostics().Where(x => x.Level == DiagnosticLevel.Error); var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(bicepContents, "\n", errors, diag => OutputHelper.GetDiagLoggingString(bicepContents, outputDirectory, diag)); Assert.Fail("Template with prefix {0} contains errors. Please fix following errors:\n {1}", completionData.Prefix, sourceTextWithDiags); } }
public static string AddDiagsToSourceText <TPositionable>(DataSet dataSet, IEnumerable <TPositionable> items, Func <TPositionable, string> diagsFunc) where TPositionable : IPositionable => OutputHelper.AddDiagsToSourceText(dataSet.Bicep, dataSet.HasCrLfNewlines() ? "\r\n" : "\n", items, item => item.Span, diagsFunc);
public static string AddDiagsToSourceText <T>(DataSet dataSet, IEnumerable <T> items, Func <T, TextSpan> getSpanFunc, Func <T, string> diagsFunc) => OutputHelper.AddDiagsToSourceText <T>(dataSet.Bicep, dataSet.HasCrLfNewlines() ? "\r\n" : "\n", items, getSpanFunc, diagsFunc);