public void GetAllDiagnostics_VerifyDisableNextLineDiagnosticsDirectiveDoesNotSupportCoreCompilerErrorSuppression() { var bicepFileContents = @"#disable-next-line BCP029 BCP068 resource test"; 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, BicepTestConstants.LinterAnalyzer); var diagnostics = compilation.GetEntrypointSemanticModel().GetAllDiagnostics(); diagnostics.Count().Should().Be(2); diagnostics.Should().SatisfyRespectively( x => { x.Level.Should().Be(DiagnosticLevel.Error); x.Code.Should().Be("BCP068"); }, x => { x.Level.Should().Be(DiagnosticLevel.Error); x.Code.Should().Be("BCP029"); }); }
private static SemanticModel GetSemanticModelForTest(string programText, INamespaceProvider nsProvider) { var configuration = BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled; var compilation = new Compilation(nsProvider, SourceFileGroupingFactory.CreateFromText(programText, BicepTestConstants.FileResolver), configuration); return(compilation.GetEntrypointSemanticModel()); }
public void GetAllDiagnostics_VerifyDisableNextLineDiagnosticsDirectiveSupportsCoreCompilerWarningSuppression() { var bicepFileContents = @"var vmProperties = { diagnosticsProfile: { bootDiagnostics: { enabled: 123 storageUri: true unknownProp: 'asdf' } } evictionPolicy: 'Deallocate' } resource vm 'Microsoft.Compute/virtualMachines@2020-12-01' = { name: 'vm' location: 'West US' #disable-next-line BCP036 BCP037 properties: vmProperties }"; 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, BicepTestConstants.LinterAnalyzer); compilation.GetEntrypointSemanticModel().GetAllDiagnostics().Should().BeEmpty(); }
public void Module_self_cycle_is_detected_correctly() { var mainUri = new Uri("file:///main.bicep"); var files = new Dictionary <Uri, string> { [mainUri] = @" param inputa string param inputb string module mainRecursive 'main.bicep' = { name: 'mainRecursive' params: { inputa: inputa inputb: inputb } } ", }; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver, Configuration), Configuration, LinterAnalyzer); var(success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation); diagnosticsByFile[mainUri].Should().HaveDiagnostics(new[] {
public void NestedResources_invalid_resource_references() { var program = @" var notResource = 'hi' resource parent 'My.RP/parentType@2020-01-01' = { name: 'parent' properties: { size: 'large' } resource child 'childType' = { name: 'child' properties: { style: 'very cool' } resource grandchild 'grandchildType' = { name: 'grandchild' properties: { temperature: 'ice-cold' } } } } output fromVariable string = notResource::child.properties.style output fromChildInvalid string = parent::child2.properties.style output fromGrandchildInvalid string = parent::child::cousin.properties.temperature "; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingMissingTypes().Should().HaveDiagnostics(new[] {
public void PrintHelper_should_add_annotations() { var bicepFile = SourceFileGroupingFactory.CreateFromText(@" resource domainServices 'Microsoft.MadeUpRp/madeUpType@2017-06-01' = { name: 'hello' location: location properties: { someMadeUpProp: 'boo' } } ", BicepTestConstants.FileResolver).EntryPoint; var output = PrintHelper.PrintWithAnnotations(bicepFile, new[] { new PrintHelper.Annotation(new TextSpan(26, 18), "what is this!?"), // 0 length span should produce a '^' rather than a '~' new PrintHelper.Annotation(new TextSpan(80, 0), "oh, hi!"), new PrintHelper.Annotation(new TextSpan(129, 14), "i can't believe you've done this"), }, 1, true); output.Should().Be( @"1| 2| resource domainServices 'Microsoft.MadeUpRp/madeUpType@2017-06-01' = { ~~~~~~~~~~~~~~~~~~ what is this!? 3| name: 'hello' ^ oh, hi! 4| location: location 5| properties: { 6| someMadeUpProp: 'boo' ~~~~~~~~~~~~~~ i can't believe you've done this 7| } "); }
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 VisitorShouldProduceNoChainForNonInlinedVariables(string variableName) { var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); VariableDeclarationSyntax variable = GetVariableByName(compilation, variableName); InlineDependencyVisitor.ShouldInlineVariable(compilation.GetEntrypointSemanticModel(), variable, out var chain).Should().BeFalse(); chain.Should().BeEmpty(); }
private static SemanticModel GetSemanticModelForTest(string programText, IEnumerable <ResourceType> definedTypes) { var typeProvider = TestTypeHelper.CreateProviderWithTypes(definedTypes); var compilation = new Compilation(typeProvider, SourceFileGroupingFactory.CreateFromText(programText, BicepTestConstants.FileResolver)); return(compilation.GetEntrypointSemanticModel()); }
public void EmptyProgram_SourceFileGrouping_should_be_persisted() { var fileResolver = new FileResolver(); var program = SourceFileGroupingFactory.CreateFromText(DataSets.Empty.Bicep, fileResolver); var compilation = new Compilation(BicepTestConstants.Features, TestTypeHelper.CreateEmptyProvider(), program, BicepTestConstants.BuiltInConfiguration, BicepTestConstants.LinterAnalyzer); compilation.SourceFileGrouping.Should().BeSameAs(program); compilation.GetEntrypointSemanticModel().Should().NotBeNull(); }
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 void Modules_can_be_compiled_successfully() { var mainUri = new Uri("file:///main.bicep"); var moduleAUri = new Uri("file:///modulea.bicep"); var moduleBUri = new Uri("file:///moduleb.bicep"); var files = new Dictionary <Uri, string> { [mainUri] = @" param inputa string param inputb string module modulea 'modulea.bicep' = { name: 'modulea' params: { inputa: inputa inputb: inputb } } module moduleb 'moduleb.bicep' = { name: 'moduleb' params: { inputa: inputa inputb: inputb } } output outputa string = modulea.outputs.outputa output outputb string = moduleb.outputs.outputb ", [moduleAUri] = @" param inputa string param inputb string output outputa string = '${inputa}-${inputb}' ", [moduleBUri] = @" param inputa string param inputb string output outputb string = '${inputa}-${inputb}' ", }; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateForFiles(files, mainUri, BicepTestConstants.FileResolver, Configuration), Configuration, LinterAnalyzer); var(success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation); diagnosticsByFile.Values.SelectMany(x => x).Should().BeEmpty(); success.Should().BeTrue(); GetTemplate(compilation).Should().NotBeEmpty(); }
public void VisitorShouldProduceCorrectChainForInlinedVariables(string variableName, string expectedChain) { var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); VariableDeclarationSyntax variable = GetVariableByName(compilation, variableName); InlineDependencyVisitor.ShouldInlineVariable(compilation.GetEntrypointSemanticModel(), variable, out var chain).Should().BeTrue(); chain.Should().NotBeNull(); var actualChain = string.Join(',', (IEnumerable <string>)chain !); actualChain.Should().Be(expectedChain); }
public void AzResourceTypeProvider_should_warn_for_missing_resource_types() { Compilation createCompilation(string program) => new Compilation(AzResourceTypeProvider.CreateWithAzTypes(), SourceFileGroupingFactory.CreateFromText(program, new Mock <IFileResolver>(MockBehavior.Strict).Object)); // Missing top-level properties - should be an error var compilation = createCompilation(@" resource missingResource 'Mock.Rp/madeUpResourceType@2020-01-01' = { name: 'missingResource' } "); compilation.Should().HaveDiagnostics(new[] {
public void VisitorShouldCalculateInliningInBulk() { var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var inlineVariables = InlineDependencyVisitor.GetVariablesToInline(compilation.GetEntrypointSemanticModel()); inlineVariables.Should().Contain(new[] { GetVariableSymbolByName(compilation, "keys"), GetVariableSymbolByName(compilation, "indirection"), GetVariableSymbolByName(compilation, "runtimeLoop"), GetVariableSymbolByName(compilation, "runtimeLoop2") }); }
public void PrintHelper_only_includes_nearby_context() { var bicepFile = SourceFileGroupingFactory.CreateFromText(@" var test = ''' here's a really long multiline string that we don't care about ''' // // give me a cursor here please! // var test = ''' here's another really long multiline string that we don't care about ''' ", BicepTestConstants.FileResolver).EntryPoint; var output = PrintHelper.PrintWithAnnotations(bicepFile, new[] { new PrintHelper.Annotation(new TextSpan(108, 4), "here's your cursor!"), }, 1, true); output.Should().Be( @"16| // 17| // give me a cursor here please! ~~~~ here's your cursor! 18| // "); }
public void GetAllDiagnostics_VerifyDisableNextLineDiagnosticsDirectiveSupportsLinterWarningSuppression() { var bicepFileContents = @"#disable-next-line no-unused-params 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, BicepTestConstants.LinterAnalyzer); compilation.GetEntrypointSemanticModel().GetAllDiagnostics().Should().BeEmpty(); }
public void TemplateEmitter_output_should_not_include_UTF8_BOM() { var sourceFileGrouping = SourceFileGroupingFactory.CreateFromText("", BicepTestConstants.FileResolver); var compiledFilePath = FileHelper.GetResultFilePath(this.TestContext, "main.json"); // emitting the template should be successful var result = this.EmitTemplate(sourceFileGrouping, BicepTestConstants.EmitterSettings, compiledFilePath); result.Diagnostics.Should().BeEmpty(); result.Status.Should().Be(EmitStatus.Succeeded); var bytes = File.ReadAllBytes(compiledFilePath); // No BOM at the start of the file bytes.Take(3).Should().NotBeEquivalentTo(new[] { 0xEF, 0xBB, 0xBF }, "BOM should not be present"); bytes.First().Should().Be(0x7B, "template should always begin with a UTF-8 encoded open curly"); bytes.Last().Should().Be(0x7D, "template should always end with a UTF-8 encoded close curly"); }
public void NestedResources_symbols_are_bound() { var program = @" resource parent 'My.RP/parentType@2020-01-01' = { name: 'parent' properties: { size: 'large' } resource child 'childType' = { name: 'child' properties: { style: 'very cool' } } resource sibling 'childType@2020-01-02' = { name: 'sibling' properties: { style: child.properties.style size: parent.properties.size } } } "; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingMissingTypes().Should().BeEmpty(); var expected = new[] { new { name = "child", type = "My.RP/parentType/childType@2020-01-01", }, new { name = "parent", type = "My.RP/parentType@2020-01-01", }, new { name = "sibling", type = "My.RP/parentType/childType@2020-01-02", }, }; model.AllResources.Select(x => x.Symbol) .Select(s => new { name = s.Name, type = (s.Type as ResourceType)?.TypeReference.FormatName(), }) .OrderBy(n => n.name) .Should().BeEquivalentTo(expected); }
public void ShouldConvertExpressionsCorrectly(string text, string expected) { var programText = $"var test = {text}"; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(programText, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var programSyntax = compilation.SourceFileGrouping.EntryPoint.ProgramSyntax; var variableDeclarationSyntax = programSyntax.Children.OfType <VariableDeclarationSyntax>().First(); var converter = new ExpressionConverter(new EmitterContext(compilation.GetEntrypointSemanticModel(), BicepTestConstants.EmitterSettings)); var converted = converter.ConvertExpression(variableDeclarationSyntax.Value); var serializer = new ExpressionSerializer(new ExpressionSerializerSettings { IncludeOuterSquareBrackets = true, SingleStringHandling = ExpressionSerializerSingleStringHandling.SerializeAsString }); var actual = serializer.SerializeExpression(converted); actual.Should().Be(expected); }
public void NestedResources_resource_can_contain_property_called_resource() { var program = @" resource parent 'My.RP/parentType@2020-01-01' = { name: 'parent' properties: { size: 'large' } resource: 'yes please' resource child 'childType' = { name: 'child' properties: { style: 'very cool' } } } "; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); var model = compilation.GetEntrypointSemanticModel(); // The property "resource" is not allowed ... model.GetAllDiagnostics().ExcludingMissingTypes().Should().HaveCount(1); model.GetAllDiagnostics().ExcludingMissingTypes().Single().Should().HaveCodeAndSeverity("BCP037", DiagnosticLevel.Error); var expected = new[] { new { name = "child", type = "My.RP/parentType/childType@2020-01-01", }, new { name = "parent", type = "My.RP/parentType@2020-01-01", }, }; model.AllResources.Select(x => x.Symbol) .Select(s => new { name = s.Name, type = (s.Type as ResourceType)?.TypeReference.FormatName(), }) .OrderBy(n => n.name) .Should().BeEquivalentTo(expected); }
public void VerifyDisableNextLineDiagnosticDirectivesCache_WithMultipleDisableNextLineDiagnosticDirectivesInBicepFile() { string bicepFileContents = @"#disable-next-line no-unused-params param storageAccount string = 'testStorageAccount' var vmProperties = { diagnosticsProfile: { bootDiagnostics: { enabled: 123 storageUri: true unknownProp: 'asdf' } } evictionPolicy: 'Deallocate' } resource vm 'Microsoft.Compute/virtualMachines@2020-12-01' = { name: 'vm' location: 'West US' #disable-next-line BCP036 BCP037 properties: vmProperties } "; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(bicepFileContents, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration, BicepTestConstants.LinterAnalyzer); var bicepFile = compilation.GetEntrypointSemanticModel().SourceFile; var disabledDiagnosticsCache = bicepFile.DisabledDiagnosticsCache; var disableNextLineDirectiveEndPositionAndCodes = disabledDiagnosticsCache.TryGetDisabledNextLineDirective(0); disableNextLineDirectiveEndPositionAndCodes.Should().NotBeNull(); disableNextLineDirectiveEndPositionAndCodes !.endPosition.Should().Be(35); disableNextLineDirectiveEndPositionAndCodes.diagnosticCodes.Should().Contain("no-unused-params"); disableNextLineDirectiveEndPositionAndCodes = disabledDiagnosticsCache.TryGetDisabledNextLineDirective(15); disableNextLineDirectiveEndPositionAndCodes.Should().NotBeNull(); disableNextLineDirectiveEndPositionAndCodes !.endPosition.Should().Be(396); disableNextLineDirectiveEndPositionAndCodes.diagnosticCodes.Should().Contain("BCP036"); disableNextLineDirectiveEndPositionAndCodes.diagnosticCodes.Should().Contain("BCP037"); }
public void VerifyDisableNextLineDiagnosticDirectivesCache_WithNoDisableNextLineDiagnosticDirectivesInBicepFile() { string bicepFileContents = @"param storageAccount string = 'testStorageAccount'"; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(bicepFileContents, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration, BicepTestConstants.LinterAnalyzer); var bicepFile = compilation.GetEntrypointSemanticModel().SourceFile; var disabledDiagnosticsCache = bicepFile.DisabledDiagnosticsCache; var disableNextLineDirectiveEndPositionAndCodes = disabledDiagnosticsCache.TryGetDisabledNextLineDirective(0); disableNextLineDirectiveEndPositionAndCodes.Should().BeNull(); }
public void NestedResources_valid_resource_references() { var program = @" resource parent 'My.RP/parentType@2020-01-01' = { name: 'parent' properties: { size: 'large' } resource child 'childType' = { name: 'child' properties: { style: 'very cool' } resource grandchild 'grandchildType' = { name: 'grandchild' properties: { temperature: 'ice-cold' } } } resource sibling 'childType@2020-01-02' = { name: 'sibling' properties: { style: parent::child.properties.style size: parent.properties.size temperatureC: child::grandchild.properties.temperature temperatureF: parent::child::grandchild.properties.temperature } } } output fromChild string = parent::child.properties.style output fromGrandchild string = parent::child::grandchild.properties.style "; var compilation = new Compilation(BicepTestConstants.Features, TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText(program, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration, BicepTestConstants.LinterAnalyzer); var model = compilation.GetEntrypointSemanticModel(); model.GetAllDiagnostics().ExcludingLinterDiagnostics().ExcludingMissingTypes().Should().BeEmpty(); var parent = model.DeclaredResources.Select(x => x.Symbol).Single(r => r.Name == "parent"); var references = model.FindReferences(parent); references.Should().HaveCount(6); var child = model.DeclaredResources.Select(x => x.Symbol).Single(r => r.Name == "child"); references = model.FindReferences(child); references.Should().HaveCount(6); var grandchild = model.DeclaredResources.Select(x => x.Symbol).Single(r => r.Name == "grandchild"); references = model.FindReferences(grandchild); references.Should().HaveCount(4); var sibling = model.DeclaredResources.Select(x => x.Symbol).Single(r => r.Name == "sibling"); references = model.FindReferences(sibling); references.Should().HaveCount(1); var emitter = new TemplateEmitter(compilation.GetEntrypointSemanticModel(), BicepTestConstants.EmitterSettings); using var outputStream = new MemoryStream(); emitter.Emit(outputStream); outputStream.Seek(0L, SeekOrigin.Begin); var text = Encoding.UTF8.GetString(outputStream.GetBuffer()); }
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 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 void AzResourceTypeProvider_should_warn_for_missing_resource_types() { var configuration = BicepTestConstants.BuiltInConfigurationWithAnalyzersDisabled; Compilation createCompilation(string program) => new Compilation(new DefaultNamespaceProvider(new AzResourceTypeLoader(), BicepTestConstants.Features), SourceFileGroupingFactory.CreateFromText(program, new Mock <IFileResolver>(MockBehavior.Strict).Object), configuration, BicepTestConstants.LinterAnalyzer); // Missing top-level properties - should be an error var compilation = createCompilation(@" resource missingResource 'Mock.Rp/madeUpResourceType@2020-01-01' = { name: 'missingResource' } "); compilation.Should().HaveDiagnostics(new[] {
public void LockedModeShouldBlockAccess() { const string expectedMessage = "Properties of the symbol context should not be accessed until name binding is completed."; var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText("", BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration, BicepTestConstants.LinterAnalyzer); var bindings = new Dictionary <SyntaxBase, Symbol>(); var cyclesBySymbol = new Dictionary <DeclaredSymbol, ImmutableArray <DeclaredSymbol> >(); var context = new SymbolContext(compilation, compilation.GetEntrypointSemanticModel()); Action byName = () => { var tm = context.TypeManager; }; byName.Should().Throw <InvalidOperationException>().WithMessage(expectedMessage); Action byNode = () => { var b = context.Compilation; }; byNode.Should().Throw <InvalidOperationException>().WithMessage(expectedMessage); context.Unlock(); context.TypeManager.Should().NotBeNull(); context.Compilation.Should().NotBeNull(); }
public void EndOfFileFollowingSpaceAfterParameterKeyWordShouldNotThrow() { var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), SourceFileGroupingFactory.CreateFromText("parameter ", BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); compilation.GetEntrypointSemanticModel().GetParseDiagnostics(); }
public void ZeroMatchingNodes_Create_ShouldThrow() { const string text = "var foo = 42"; var compilation = new Compilation(BicepTestConstants.NamespaceProvider, SourceFileGroupingFactory.CreateFromText(text, BicepTestConstants.FileResolver), BicepTestConstants.BuiltInConfiguration); Action fail = () => BicepCompletionContext.Create(BicepTestConstants.Features, compilation, text.Length + 2); fail.Should().Throw <ArgumentException>().WithMessage("The specified offset 14 is outside the span of the specified ProgramSyntax node."); }