public void AzResourceTypeProvider_can_deserialize_all_types_without_throwing(ResourceTypeGenerationFlags flags) { var resourceTypeProvider = AzResourceTypeProvider.CreateWithAzTypes(); var availableTypes = resourceTypeProvider.GetAvailableTypes(); // sanity check - we know there should be a lot of types available var expectedTypeCount = 3000; availableTypes.Should().HaveCountGreaterThan(expectedTypeCount); foreach (var availableType in availableTypes) { resourceTypeProvider.HasType(availableType).Should().BeTrue(); var resourceType = resourceTypeProvider.GetType(availableType, flags); try { var visited = new HashSet <TypeSymbol>(); VisitAllReachableTypes(resourceType, visited); } catch (Exception exception) { throw new InvalidOperationException($"Deserializing type {availableType.FormatName()} failed", exception); } } }
public static int Main(string[] args) { BicepDeploymentsInterop.Initialize(); var program = new Program(AzResourceTypeProvider.CreateWithAzTypes(), Console.Out, Console.Error, ThisAssembly.AssemblyFileVersion); return(program.Run(args)); }
public static Compilation CopyFilesAndCreateCompilation(this DataSet dataSet, TestContext testContext, out string outputDirectory, out Uri fileUri) { outputDirectory = dataSet.SaveFilesToTestDirectory(testContext); fileUri = PathHelper.FilePathToFileUrl(Path.Combine(outputDirectory, DataSet.TestFileMain)); var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(BicepTestConstants.FileResolver, new Workspace(), fileUri); return(new Compilation(AzResourceTypeProvider.CreateWithAzTypes(), syntaxTreeGrouping)); }
public void VisitorShouldProduceNoChainForNonInlinedVariables(string variableName) { var compilation = new Compilation(AzResourceTypeProvider.CreateWithAzTypes(), SyntaxTreeGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver)); VariableDeclarationSyntax variable = GetVariableByName(compilation, variableName); InlineDependencyVisitor.ShouldInlineVariable(compilation.GetEntrypointSemanticModel(), variable, out var chain).Should().BeFalse(); chain.Should().BeEmpty(); }
public void AzResourceTypeProvider_can_deserialize_all_types_without_throwing(ResourceTypeGenerationFlags flags) { var resourceTypeProvider = AzResourceTypeProvider.CreateWithAzTypes(); var availableTypes = resourceTypeProvider.GetAvailableTypes(); // sanity check - we know there should be a lot of types available var expectedTypeCount = 3000; availableTypes.Should().HaveCountGreaterThan(expectedTypeCount); foreach (var availableType in availableTypes) { resourceTypeProvider.HasType(availableType).Should().BeTrue(); var resourceType = resourceTypeProvider.GetType(availableType, flags); try { var visited = new HashSet <TypeSymbol>(); VisitAllReachableTypes(resourceType, visited); } catch (Exception exception) { throw new InvalidOperationException($"Deserializing type {availableType.FormatName()} failed", exception); } bool IsSymbolicProperty(TypeProperty property) { var type = property.TypeReference.Type; return(type is IScopeReference || type == LanguageConstants.ResourceOrResourceCollectionRefItem || type == LanguageConstants.ResourceOrResourceCollectionRefArray); } /* * This test is the most expensive one because it deserializes all the types. * Creating a separate test to add a bit of extra validation would basically double the runtime of the Az provider tests. */ { // some types include a top-level scope property that is different than our own scope property // so we need to filter by type var topLevelProperties = GetTopLevelProperties(resourceType); var symbolicProperties = topLevelProperties.Where(property => IsSymbolicProperty(property)); symbolicProperties.Should().NotBeEmpty(); symbolicProperties.Should().OnlyContain(property => property.Flags.HasFlag(TypePropertyFlags.DisallowAny), $"because all symbolic properties in type '{availableType.FullyQualifiedType}' and api version '{availableType.ApiVersion}' should have the {nameof(TypePropertyFlags.DisallowAny)} flag."); var loopVariantProperties = topLevelProperties.Where(property => ExpectedLoopVariantProperties.Contains(property.Name) && (!string.Equals(property.Name, LanguageConstants.ResourceScopePropertyName, LanguageConstants.IdentifierComparison) || IsSymbolicProperty(property))); loopVariantProperties.Should().NotBeEmpty(); loopVariantProperties.Should().OnlyContain(property => property.Flags.HasFlag(TypePropertyFlags.LoopVariant), $"because all loop variant properties in type '{availableType.FullyQualifiedType}' and api version '{availableType.ApiVersion}' should have the {nameof(TypePropertyFlags.LoopVariant)} flag."); if (flags.HasFlag(ResourceTypeGenerationFlags.NestedResource)) { // syntactically nested resources should not have the parent property topLevelProperties.Should().NotContain(property => string.Equals(property.Name, LanguageConstants.ResourceParentPropertyName, LanguageConstants.IdentifierComparison)); } } } }
public void ZeroMatchingNodes_Create_ShouldThrow() { const string text = "var foo = 42"; var compilation = new Compilation(AzResourceTypeProvider.CreateWithAzTypes(), SyntaxTreeGroupingFactory.CreateFromText(text)); Action fail = () => BicepCompletionContext.Create(compilation, text.Length + 2); fail.Should().Throw <ArgumentException>().WithMessage("The specified offset 14 is outside the span of the specified ProgramSyntax node."); }
public void AzResourceTypeProvider_can_list_all_types_without_throwing() { var resourceTypeProvider = AzResourceTypeProvider.CreateWithAzTypes(); var availableTypes = resourceTypeProvider.GetAvailableTypes(); // sanity check - we know there should be a lot of types available var expectedTypeCount = 3000; availableTypes.Should().HaveCountGreaterThan(expectedTypeCount); }
public void VisitorShouldProduceCorrectChainForInlinedVariables(string variableName, string expectedChain) { var compilation = new Compilation(AzResourceTypeProvider.CreateWithAzTypes(), SyntaxTreeGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver)); 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(), SyntaxTreeGroupingFactory.CreateFromText(program)); // 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(AzResourceTypeProvider.CreateWithAzTypes(), SyntaxTreeGroupingFactory.CreateFromText(Text, BicepTestConstants.FileResolver)); var inlineVariables = InlineDependencyVisitor.GetVariablesToInline(compilation.GetEntrypointSemanticModel()); inlineVariables.Should().Contain(new[] { GetVariableSymbolByName(compilation, "keys"), GetVariableSymbolByName(compilation, "indirection"), GetVariableSymbolByName(compilation, "runtimeLoop"), GetVariableSymbolByName(compilation, "runtimeLoop2") }); }
public static int Main(string[] args) { string profilePath = MulticoreJIT.GetMulticoreJITPath(); ProfileOptimization.SetProfileRoot(profilePath); ProfileOptimization.StartProfile("bicep.profile"); Console.OutputEncoding = TemplateEmitter.UTF8EncodingWithoutBom; BicepDeploymentsInterop.Initialize(); var program = new Program(new InvocationContext(AzResourceTypeProvider.CreateWithAzTypes(), Console.Out, Console.Error, ThisAssembly.AssemblyFileVersion)); return(program.Run(args)); }
public static async Task Main(string[] args) => await RunWithCancellationAsync(async cancellationToken => { // the server uses JSON-RPC over stdin & stdout to communicate, // so be careful not to use console for logging! var server = new Server( Console.OpenStandardInput(), Console.OpenStandardOutput(), new Server.CreationOptions { ResourceTypeProvider = AzResourceTypeProvider.CreateWithAzTypes(), FileResolver = new FileResolver(), }); await server.RunAsync(cancellationToken); });
public void AzResourceTypeProvider_can_deserialize_all_types_without_throwing(ResourceTypeGenerationFlags flags) { var resourceTypeProvider = AzResourceTypeProvider.CreateWithAzTypes(); var availableTypes = resourceTypeProvider.GetAvailableTypes(); // sanity check - we know there should be a lot of types available var expectedTypeCount = 3000; availableTypes.Should().HaveCountGreaterThan(expectedTypeCount); foreach (var availableType in availableTypes) { resourceTypeProvider.HasType(availableType).Should().BeTrue(); var resourceType = resourceTypeProvider.GetType(availableType, flags); try { var visited = new HashSet <TypeSymbol>(); VisitAllReachableTypes(resourceType, visited); } catch (Exception exception) { throw new InvalidOperationException($"Deserializing type {availableType.FormatName()} failed", exception); } bool IsSymbolicProperty(TypeProperty property) { var type = property.TypeReference.Type; return(type is IScopeReference || type == LanguageConstants.ResourceOrResourceCollectionRefItem || type == LanguageConstants.ResourceOrResourceCollectionRefArray); } /* * This test is the most expensive one because it deserializes all the types. * Creating a separate test to add a bit of extra validation would basically double the runtime of the Az provider tests. */ { // some types include a top-level scope property that is different than our own scope property // so we need to filter by type var topLevelProperties = GetTopLevelProperties(resourceType); var symbolicProperties = topLevelProperties.Where(property => IsSymbolicProperty(property)); symbolicProperties.Should().NotBeEmpty(); symbolicProperties.Should().OnlyContain(property => property.Flags.HasFlag(TypePropertyFlags.DisallowAny)); } } }
public static async Task Main() => await RunWithCancellationAsync(async cancellationToken => { string profilePath = MulticoreJIT.GetMulticoreJITPath(); ProfileOptimization.SetProfileRoot(profilePath); ProfileOptimization.StartProfile("bicepserver.profile"); // the server uses JSON-RPC over stdin & stdout to communicate, // so be careful not to use console for logging! var server = new Server( Console.OpenStandardInput(), Console.OpenStandardOutput(), new Server.CreationOptions { ResourceTypeProvider = AzResourceTypeProvider.CreateWithAzTypes(), FileResolver = new FileResolver() }); await server.RunAsync(cancellationToken); });
public void Decompiler_generates_expected_bicep_files_with_diagnostics(ExampleData example) { // save all the files in the containing directory to disk so that we can test module resolution var parentStream = Path.GetDirectoryName(example.BicepStreamName) !.Replace('\\', '/'); var outputDirectory = FileHelper.SaveEmbeddedResourcesWithPathPrefix(TestContext, typeof(DecompilationTests).Assembly, parentStream); var bicepFileName = Path.Combine(outputDirectory, Path.GetFileName(example.BicepStreamName)); var jsonFileName = Path.Combine(outputDirectory, Path.GetFileName(example.JsonStreamName)); var typeProvider = AzResourceTypeProvider.CreateWithAzTypes(); var(bicepUri, filesToSave) = TemplateDecompiler.DecompileFileWithModules(typeProvider, new FileResolver(), PathHelper.FilePathToFileUrl(jsonFileName)); var syntaxTrees = filesToSave.Select(kvp => SyntaxTree.Create(kvp.Key, kvp.Value)); var workspace = new Workspace(); workspace.UpsertSyntaxTrees(syntaxTrees); var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), workspace, bicepUri); var compilation = new Compilation(typeProvider, syntaxTreeGrouping); var diagnosticsBySyntaxTree = compilation.GetAllDiagnosticsBySyntaxTree(); using (new AssertionScope()) { foreach (var syntaxTree in syntaxTreeGrouping.SyntaxTrees) { var exampleExists = File.Exists(syntaxTree.FileUri.LocalPath); exampleExists.Should().BeTrue($"Generated example \"{syntaxTree.FileUri.LocalPath}\" should be checked in"); var diagnostics = diagnosticsBySyntaxTree[syntaxTree]; var bicepOutput = filesToSave[syntaxTree.FileUri]; var sourceTextWithDiags = OutputHelper.AddDiagsToSourceText(bicepOutput, Environment.NewLine, diagnostics, diag => OutputHelper.GetDiagLoggingString(bicepOutput, outputDirectory, diag)); File.WriteAllText(syntaxTree.FileUri.LocalPath + ".actual", sourceTextWithDiags); sourceTextWithDiags.Should().EqualWithLineByLineDiffOutput( TestContext, exampleExists ? File.ReadAllText(syntaxTree.FileUri.LocalPath) : "", expectedLocation: Path.Combine("src", "Bicep.Decompiler.IntegrationTests", parentStream, Path.GetRelativePath(outputDirectory, syntaxTree.FileUri.LocalPath)), actualLocation: syntaxTree.FileUri.LocalPath + ".actual"); } } }
private async Task <BicepTelemetryEvent> ResolveCompletionAsync(string text, string prefix, Position position) { var fileSystemDict = new Dictionary <Uri, string>(); var telemetryReceived = new TaskCompletionSource <BicepTelemetryEvent>(); var client = await IntegrationTestHelper.StartServerWithClientConnectionAsync( TestContext, options => { options.OnTelemetryEvent <BicepTelemetryEvent>(telemetry => telemetryReceived.SetResult(telemetry)); }, resourceTypeProvider : AzResourceTypeProvider.CreateWithAzTypes(), fileResolver : new InMemoryFileResolver(fileSystemDict)); 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 async Task HoveringOverSymbolReferencesAndDeclarationsShouldProduceHovers(DataSet dataSet) { var compilation = dataSet.CopyFilesAndCreateCompilation(TestContext, out _, out var fileUri); var uri = DocumentUri.From(fileUri); var client = await IntegrationTestHelper.StartServerWithTextAsync(this.TestContext, dataSet.Bicep, uri, resourceTypeProvider : AzResourceTypeProvider.CreateWithAzTypes(), fileResolver : BicepTestConstants.FileResolver); var symbolTable = compilation.ReconstructSymbolTable(); var lineStarts = compilation.SyntaxTreeGrouping.EntryPoint.LineStarts; var symbolReferences = SyntaxAggregator.Aggregate( compilation.SyntaxTreeGrouping.EntryPoint.ProgramSyntax, new List <SyntaxBase>(), (accumulated, node) => { if (node is ISymbolReference || node is ITopLevelNamedDeclarationSyntax) { accumulated.Add(node); } return(accumulated); }, accumulated => accumulated); foreach (var symbolReference in symbolReferences) { // by default, request a hover on the first character of the syntax, but for certain syntaxes, this doesn't make sense. // for example on an instance function call 'az.resourceGroup()', it only makes sense to request a hover on the 3rd character. var nodeForHover = symbolReference switch { ITopLevelDeclarationSyntax d => d.Keyword, ResourceAccessSyntax r => r.ResourceName, FunctionCallSyntaxBase f => f.Name, _ => symbolReference, }; var hover = await client.RequestHover(new HoverParams { TextDocument = new TextDocumentIdentifier(uri), Position = TextCoordinateConverter.GetPosition(lineStarts, nodeForHover.Span.Position) }); // fancy method to give us some annotated source code to look at if any assertions fail :) using (new AssertionScope().WithVisualCursor(compilation.SyntaxTreeGrouping.EntryPoint, nodeForHover.Span.ToZeroLengthSpan())) { if (!symbolTable.TryGetValue(symbolReference, out var symbol)) { if (symbolReference is InstanceFunctionCallSyntax && compilation.GetEntrypointSemanticModel().GetSymbolInfo(symbolReference) is FunctionSymbol ifcSymbol) { ValidateHover(hover, ifcSymbol); break; } // symbol ref not bound to a symbol hover.Should().BeNull(); continue; } switch (symbol !.Kind) {
private static void RegisterServices(CreationOptions creationOptions, IServiceCollection services) { // using type based registration so dependencies can be injected automatically // without manually constructing up the graph services.AddSingleton <IResourceTypeProvider>(services => creationOptions.ResourceTypeProvider ?? AzResourceTypeProvider.CreateWithAzTypes()); services.AddSingleton <ISnippetsProvider>(services => creationOptions.SnippetsProvider ?? new SnippetsProvider()); services.AddSingleton <IFileResolver>(services => creationOptions.FileResolver ?? new FileResolver()); services.AddSingleton <IWorkspace, Workspace>(); services.AddSingleton <ICompilationManager, BicepCompilationManager>(); services.AddSingleton <ICompilationProvider, BicepCompilationProvider>(); services.AddSingleton <ISymbolResolver, BicepSymbolResolver>(); services.AddSingleton <ICompletionProvider, BicepCompletionProvider>(); }