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);
                }
            }
        }
Пример #2
0
        public static int Main(string[] args)
        {
            BicepDeploymentsInterop.Initialize();
            var program = new Program(AzResourceTypeProvider.CreateWithAzTypes(), Console.Out, Console.Error, ThisAssembly.AssemblyFileVersion);

            return(program.Run(args));
        }
Пример #3
0
        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));
        }
Пример #4
0
        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();
        }
Пример #5
0
        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);
        }
Пример #8
0
        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 [] {
Пример #10
0
        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")
            });
        }
Пример #11
0
        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));
        }
Пример #12
0
        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);
        });
Пример #13
0
        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));
                }
            }
        }
Пример #14
0
        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);
        });
Пример #15
0
        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");
                }
            }
        }
Пример #16
0
        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));
        }
Пример #17
0
        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)
                    {
Пример #18
0
 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>();
 }