Пример #1
0
        public void ParameterTypeContextShouldIncludeFunctionsValidInDefaultValues()
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(@"param p string = 's'"));

            compilation.GetEntrypointSemanticModel().GetAllDiagnostics().Should().BeEmpty();

            var parameter = compilation.SyntaxTreeGrouping.EntryPoint.ProgramSyntax.Children.OfType <ParameterDeclarationSyntax>().Single();

            var provider    = new BicepCompletionProvider();
            var completions = provider.GetFilteredCompletions(
                compilation.GetEntrypointSemanticModel(),
                new BicepCompletionContext(BicepCompletionContextKind.None, enclosingDeclaration: parameter)).ToList();

            AssertExpectedFunctions(completions, expectParamDefaultFunctions: true);

            // outputs can't be referenced so they should not show up in completions
            completions.Where(c => c.Kind == SymbolKind.Output.ToCompletionItemKind()).Should().BeEmpty();

            completions.Where(c => c.Kind == SymbolKind.Variable.ToCompletionItemKind()).Should().BeEmpty();
            completions.Where(c => c.Kind == SymbolKind.Resource.ToCompletionItemKind()).Should().BeEmpty();
            completions.Where(c => c.Kind == SymbolKind.Module.ToCompletionItemKind()).Should().BeEmpty();

            // should not see parameter completions because we set the enclosing declaration which will exclude the corresponding symbol
            // this avoids cycle suggestions
            completions.Where(c => c.Kind == SymbolKind.Parameter.ToCompletionItemKind()).Should().BeEmpty();
        }
Пример #2
0
        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(TestResourceTypeProvider.Create(), SyntaxTreeGroupingFactory.CreateFromText(program));
            var model       = compilation.GetEntrypointSemanticModel();

            model.GetAllDiagnostics().Should().HaveDiagnostics(new [] {
Пример #3
0
        public void CompletionsForModifierDefaultValuesShouldIncludeFunctionsValidInDefaultValues()
        {
            var grouping = SyntaxTreeGroupingFactory.CreateFromText(@"param p string {
  defaultValue: 
}");

            var offset = ((ObjectSyntax)grouping.EntryPoint.ProgramSyntax.Declarations.OfType <ParameterDeclarationSyntax>().Single().Modifier !).Properties.Single().Value.Span.Position;

            var compilation = new Compilation(TestResourceTypeProvider.Create(), grouping);
            var context     = BicepCompletionContext.Create(compilation, offset);

            var provider    = new BicepCompletionProvider(new FileResolver(), new SnippetsProvider());
            var completions = provider.GetFilteredCompletions(compilation, context).ToList();

            AssertExpectedFunctions(completions, expectParamDefaultFunctions: true);

            // outputs can't be referenced so they should not show up in completions
            completions.Where(c => c.Kind == SymbolKind.Output.ToCompletionItemKind()).Should().BeEmpty();

            completions.Where(c => c.Kind == SymbolKind.Variable.ToCompletionItemKind()).Should().BeEmpty();
            completions.Where(c => c.Kind == SymbolKind.Resource.ToCompletionItemKind()).Should().BeEmpty();
            completions.Where(c => c.Kind == SymbolKind.Module.ToCompletionItemKind()).Should().BeEmpty();

            // should not see parameter completions because we set the enclosing declaration which will exclude the corresponding symbol
            // this avoids cycle suggestions
            completions.Where(c => c.Kind == SymbolKind.Parameter.ToCompletionItemKind()).Should().BeEmpty();
        }
Пример #4
0
        public async Task HighlightsShouldShowAllReferencesOfTheSymbol(DataSet dataSet)
        {
            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var symbolToSyntaxLookup = symbolTable
                                       .Where(pair => pair.Value.Kind != SymbolKind.Error)
                                       .ToLookup(pair => pair.Value, pair => pair.Key);

            foreach (var(syntax, symbol) in symbolTable.Where(s => s.Value.Kind != SymbolKind.Error))
            {
                var highlights = await client.RequestDocumentHighlight(new DocumentHighlightParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = IntegrationTestHelper.GetPosition(lineStarts, syntax)
                });

                // calculate expected highlights
                var expectedHighlights = symbolToSyntaxLookup[symbol].Select(node => CreateExpectedHighlight(lineStarts, node));

                // ranges should match what we got from our own symbol table
                highlights.Should().BeEquivalentTo(expectedHighlights);
            }
        }
Пример #5
0
        public async Task RenamingFunctionsShouldProduceEmptyEdit(DataSet dataSet)
        {
            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var validFunctionCallPairs = symbolTable
                                         .Where(pair => pair.Value.Kind == SymbolKind.Function)
                                         .Select(pair => pair.Key);

            foreach (var syntax in validFunctionCallPairs)
            {
                var edit = await client.RequestRename(new RenameParams
                {
                    NewName      = "NewIdentifier",
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = IntegrationTestHelper.GetPosition(lineStarts, syntax)
                });

                edit.DocumentChanges.Should().BeNullOrEmpty();
                edit.Changes.Should().BeNull();
            }
        }
Пример #6
0
        public void ParameterTypeContextShouldReturnDeclarationTypeCompletions()
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(string.Empty));
            var provider    = new BicepCompletionProvider();

            var completions = provider.GetFilteredCompletions(compilation.GetEntrypointSemanticModel(), new BicepCompletionContext(BicepCompletionContextKind.ParameterType));
            var declarationTypeCompletions = completions.Where(c => c.Kind == CompletionItemKind.Class).ToList();

            AssertExpectedDeclarationTypeCompletions(declarationTypeCompletions);

            completions.Where(c => c.Kind == CompletionItemKind.Snippet).Should().SatisfyRespectively(
                c =>
            {
                c.Label.Should().Be("secureObject");
                c.Kind.Should().Be(CompletionItemKind.Snippet);
                c.InsertTextFormat.Should().Be(InsertTextFormat.Snippet);
                c.InsertText.Should().StartWith("object");
                c.InsertText.Should().Contain("secure: true");
                c.Detail.Should().Be("Secure object");
            },
                c =>
            {
                c.Label.Should().Be("secureString");
                c.Kind.Should().Be(CompletionItemKind.Snippet);
                c.InsertTextFormat.Should().Be(InsertTextFormat.Snippet);
                c.InsertText.Should().StartWith("string");
                c.InsertText.Should().Contain("secure: true");
                c.Detail.Should().Be("Secure string");
            });
        }
Пример #7
0
        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);
        }
Пример #8
0
        public static Compilation CopyFilesAndCreateCompilation(this DataSet dataSet, TestContext testContext, out string outputDirectory)
        {
            outputDirectory = dataSet.SaveFilesToTestDirectory(testContext, dataSet.Name);
            var syntaxTreeGrouping = SyntaxTreeGroupingBuilder.Build(new FileResolver(), Path.Combine(outputDirectory, DataSet.TestFileMain));

            return(new Compilation(TestResourceTypeProvider.Create(), syntaxTreeGrouping));
        }
Пример #9
0
        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(TestResourceTypeProvider.Create(), SyntaxTreeGroupingFactory.CreateForFiles(files, mainUri));

            var(success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation);
            diagnosticsByFile[mainUri].Should().HaveDiagnostics(new[] {
Пример #10
0
        public static async Task <ILanguageClient> StartServerWithClientConnectionAsync(Action <LanguageClientOptions> onClientOptions, IResourceTypeProvider?resourceTypeProvider = null, IFileResolver?fileResolver = null)
        {
            resourceTypeProvider ??= TestResourceTypeProvider.Create();
            fileResolver ??= new InMemoryFileResolver(new Dictionary <Uri, string>());

            var clientPipe = new Pipe();
            var serverPipe = new Pipe();

            var server = new Server(
                serverPipe.Reader,
                clientPipe.Writer,
                new Server.CreationOptions
            {
                ResourceTypeProvider = resourceTypeProvider,
                FileResolver         = fileResolver,
            });
            var _ = server.RunAsync(CancellationToken.None); // do not wait on this async method, or you'll be waiting a long time!

            var client = LanguageClient.PreInit(options =>
            {
                options
                .WithInput(clientPipe.Reader)
                .WithOutput(serverPipe.Writer);

                onClientOptions(options);
            });
            await client.Initialize(CancellationToken.None);

            return(client);
        }
Пример #11
0
        public void LockedModeShouldBlockAccess()
        {
            const string expectedMessage = "Properties of the symbol context should not be accessed until name binding is completed.";

            var compilation    = new Compilation(TestResourceTypeProvider.Create(), SyntaxTreeGroupingFactory.CreateFromText(""));
            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();
        }
Пример #12
0
        public async Task GoToDefinitionRequestOnUnsupportedOrInvalidSyntaxNodeShouldReturnEmptyResponse(DataSet dataSet)
        {
            var uri = DocumentUri.From($"/{dataSet.Name}");

            using var client = await IntegrationTestHelper.StartServerWithText(dataSet.Bicep, uri);

            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var symbolTable = compilation.ReconstructSymbolTable();
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);

            var undeclaredSymbolBindings = symbolTable.Where(pair => !(pair.Value is DeclaredSymbol));

            foreach (var(syntax, _) in undeclaredSymbolBindings)
            {
                var response = await client.RequestDefinition(new DefinitionParams
                {
                    TextDocument = new TextDocumentIdentifier(uri),
                    Position     = PositionHelper.GetPosition(lineStarts, syntax.Span.Position)
                });

                // go to definition on a symbol that isn't declared by the user (like error or function symbol)
                // should produce an empty response
                response.Should().BeEmpty();
            }
        }
Пример #13
0
        public void LockedModeShouldBlockAccess()
        {
            const string expectedMessage = "Properties of the symbol context should not be accessed until name binding is completed.";

            var bindings       = new Dictionary <SyntaxBase, Symbol>();
            var cyclesBySyntax = new Dictionary <SyntaxBase, ImmutableArray <DeclaredSymbol> >();
            var context        = new SymbolContext(new TypeManager(TestResourceTypeProvider.Create(), bindings, cyclesBySyntax), bindings);

            Action byName = () =>
            {
                var tm = context.TypeManager;
            };

            byName.Should().Throw <InvalidOperationException>().WithMessage(expectedMessage);

            Action byNode = () =>
            {
                var b = context.Bindings;
            };

            byNode.Should().Throw <InvalidOperationException>().WithMessage(expectedMessage);

            context.Unlock();
            context.TypeManager.Should().NotBeNull();
            context.Bindings.Should().NotBeNull();
        }
Пример #14
0
        private EmitResult EmitTemplate(string text, string filePath)
        {
            var compilation = new Compilation(TestResourceTypeProvider.CreateRegistrar(), SyntaxFactory.CreateFromText(text));
            var emitter     = new TemplateEmitter(compilation.GetSemanticModel());

            using var stream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
            return(emitter.Emit(stream));
        }
Пример #15
0
        private EmitResult EmitTemplate(SyntaxTreeGrouping syntaxTreeGrouping, string filePath)
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), syntaxTreeGrouping);
            var emitter     = new TemplateEmitter(compilation.GetEntrypointSemanticModel());

            using var stream = new FileStream(filePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
            return(emitter.Emit(stream));
        }
Пример #16
0
        public void EmptyProgram_SyntaxTreeGrouping_should_be_persisted()
        {
            var program     = SyntaxFactory.CreateFromText(DataSets.Empty.Bicep);
            var compilation = new Compilation(TestResourceTypeProvider.Create(), program);

            compilation.SyntaxTreeGrouping.Should().BeSameAs(program);
            compilation.GetEntrypointSemanticModel().Should().NotBeNull();
        }
Пример #17
0
        public void EmptyProgram_SyntaxNodeShouldBePersisted()
        {
            var program     = SyntaxFactory.CreateFromText(DataSets.Empty.Bicep);
            var compilation = new Compilation(TestResourceTypeProvider.Create(), program);

            compilation.ProgramSyntax.Should().BeSameAs(program);
            compilation.GetSemanticModel().Should().NotBeNull();
        }
Пример #18
0
        private EmitResult EmitTemplate(SyntaxTreeGrouping syntaxTreeGrouping, MemoryStream memoryStream)
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), syntaxTreeGrouping);
            var emitter     = new TemplateEmitter(compilation.GetEntrypointSemanticModel());

            TextWriter tw = new StreamWriter(memoryStream);

            return(emitter.Emit(tw));
        }
Пример #19
0
        public void DeclarationContextShouldReturnKeywordCompletions()
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(string.Empty));

            compilation.GetEntrypointSemanticModel().GetAllDiagnostics().Should().BeEmpty();

            var provider = new BicepCompletionProvider();

            var completions = provider.GetFilteredCompletions(compilation.GetEntrypointSemanticModel(), new BicepCompletionContext(BicepCompletionContextKind.DeclarationStart));

            var keywordCompletions = completions
                                     .Where(c => c.Kind == CompletionItemKind.Keyword)
                                     .OrderBy(c => c.Label)
                                     .ToList();

            keywordCompletions.Should().SatisfyRespectively(
                c =>
            {
                c.Label.Should().Be("module");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be("module");
                c.Detail.Should().Be("Module keyword");
            },
                c =>
            {
                c.Label.Should().Be("output");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be("output");
                c.Detail.Should().Be("Output keyword");
            },
                c =>
            {
                c.Label.Should().Be("param");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be("param");
                c.Detail.Should().Be("Parameter keyword");
            },
                c =>
            {
                c.Label.Should().Be("resource");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be("resource");
                c.Detail.Should().Be("Resource keyword");
            },
                c =>
            {
                c.Label.Should().Be("var");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be("var");
                c.Detail.Should().Be("Variable keyword");
            });
        }
Пример #20
0
        public void Decompiler_raises_errors_for_unsupported_features(string resourcePath, string expectedMessage)
        {
            Action onDecompile = () => {
                var fileResolver = ReadResourceFile(resourcePath);
                TemplateDecompiler.DecompileFileWithModules(TestResourceTypeProvider.Create(), fileResolver, new Uri($"file:///{resourcePath}"));
            };

            onDecompile.Should().Throw <ConversionFailedException>().WithMessage(expectedMessage);
        }
Пример #21
0
        private EmitResult EmitTemplate(string text, MemoryStream memoryStream)
        {
            var compilation = new Compilation(TestResourceTypeProvider.CreateRegistrar(), SyntaxFactory.CreateFromText(text));
            var emitter     = new TemplateEmitter(compilation.GetSemanticModel());

            TextWriter tw = new StreamWriter(memoryStream);

            return(emitter.Emit(tw));
        }
Пример #22
0
        public void DeclarationSnippetsShouldBeValid()
        {
            var grouping    = SyntaxTreeGroupingFactory.CreateFromText(string.Empty);
            var compilation = new Compilation(TestResourceTypeProvider.Create(), grouping);

            compilation.GetEntrypointSemanticModel().GetAllDiagnostics().Should().BeEmpty();

            var provider = new BicepCompletionProvider(new FileResolver());

            var completions = provider.GetFilteredCompletions(compilation, BicepCompletionContext.Create(grouping.EntryPoint, 0));

            var snippetCompletions = completions
                                     .Where(c => c.Kind == CompletionItemKind.Snippet)
                                     .OrderBy(c => c.Label)
                                     .ToList();

            snippetCompletions.Should().OnlyContain(c => c.Kind == CompletionItemKind.Snippet && c.InsertTextFormat == InsertTextFormat.Snippet);
            snippetCompletions.Should().OnlyContain(c => c.InsertTextFormat == InsertTextFormat.Snippet);
            snippetCompletions.Should().OnlyContain(c => LanguageConstants.DeclarationKeywords.Contains(c.Label));
            snippetCompletions.Should().OnlyContain(c => c.Documentation !.HasMarkupContent && c.Documentation.MarkupContent !.Kind == MarkupKind.Markdown);

            var snippetsByDetail = snippetCompletions.Where(c => c.Detail != null).ToImmutableDictionaryExcludingNull(c => c.Detail, StringComparer.Ordinal);

            var replacementsByDetail = new Dictionary <string, IList <string> >
            {
                ["Module declaration"]    = new[] { string.Empty, "myModule", "./empty.bicep" },
                ["Parameter declaration"] = new[] { string.Empty, "myParam", "string" },
                ["Parameter declaration with default value"] = new[] { string.Empty, "myParam", "string", "'myDefault'" },
                ["Parameter declaration with default and allowed values"] = new[] { string.Empty, "myParam", "string", "'myDefault'", "'val1'\n'val2'" },
                ["Parameter declaration with options"] = new[] { string.Empty, "myParam", "string", "default: 'myDefault'\nsecure: true" },
                ["Secure string parameter"]            = new[] { string.Empty, "myParam" },
                ["Variable declaration"]            = new[] { "'stringVal'", "myVariable" },
                ["Resource with defaults"]          = new[] { "prop1: 'val1'", "myResource", "myProvider", "myType", "2020-01-01", "'parent'", "'West US'" },
                ["Child Resource with defaults"]    = new[] { "prop1: 'val1'", "myResource", "myProvider", "myType", "myChildType", "2020-01-01", "'parent/child'" },
                ["Resource without defaults"]       = new[] { "properties: {\nprop1: 'val1'\n}", "myResource", "myProvider", "myType", "2020-01-01", "'parent'" },
                ["Child Resource without defaults"] = new[] { "properties: {\nprop1: 'val1'\n}", "myResource", "myProvider", "myType", "myChildType", "2020-01-01", "'parent/child'" },
                ["Output declaration"] = new[] { "'stringVal'", "myOutput", "string" }
            };

            snippetsByDetail.Keys.Should().BeEquivalentTo(replacementsByDetail.Keys);


            foreach (var(detail, completion) in snippetsByDetail)
            {
                // validate snippet
                var snippet = new Snippet(completion.TextEdit !.NewText);

                // if we don't have placeholders, why is it a snippet?
                snippet.Placeholders.Should().NotBeEmpty();

                // documentation should have the snippet without placeholders
                completion.Documentation !.MarkupContent !.Value.Should().Contain(snippet.FormatDocumentation());

                // perform the sample replacement
                var replacements = replacementsByDetail[detail !];
Пример #23
0
        public void NonDeclarationContextShouldReturnDeclarationTypeCompletions()
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(string.Empty));
            var provider    = new BicepCompletionProvider();

            var completions = provider.GetFilteredCompletions(compilation.GetSemanticModel(), new BicepCompletionContext(BicepCompletionContextKind.None));
            var declarationTypeCompletions = completions.Where(c => c.Kind == CompletionItemKind.Class).ToList();

            declarationTypeCompletions.Should().SatisfyRespectively(
                c =>
            {
                const string expected = "array";
                c.Label.Should().Be(expected);
                c.Kind.Should().Be(CompletionItemKind.Class);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be(expected);
                c.Detail.Should().Be(expected);
            },
                c =>
            {
                const string expected = "bool";
                c.Label.Should().Be(expected);
                c.Kind.Should().Be(CompletionItemKind.Class);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be(expected);
                c.Detail.Should().Be(expected);
            },
                c =>
            {
                const string expected = "int";
                c.Label.Should().Be(expected);
                c.Kind.Should().Be(CompletionItemKind.Class);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be(expected);
                c.Detail.Should().Be(expected);
            },
                c =>
            {
                const string expected = "object";
                c.Label.Should().Be(expected);
                c.Kind.Should().Be(CompletionItemKind.Class);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be(expected);
                c.Detail.Should().Be(expected);
            },
                c =>
            {
                const string expected = "string";
                c.Label.Should().Be(expected);
                c.Kind.Should().Be(CompletionItemKind.Class);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().Be(expected);
                c.Detail.Should().Be(expected);
            });
        }
Пример #24
0
        public void Create_ShouldReturnValidCompilation()
        {
            var provider = new BicepCompilationProvider(TestResourceTypeProvider.CreateRegistrar());

            var context = provider.Create(DataSets.Parameters_LF.Bicep);

            context.Compilation.Should().NotBeNull();
            context.Compilation.GetSemanticModel().GetAllDiagnostics().Should().BeEmpty();
            context.LineStarts.Should().NotBeEmpty();
            context.LineStarts[0].Should().Be(0);
        }
Пример #25
0
        public async Task RequestingCodeActionWithFixableDiagnosticsShouldProduceQuickFixes(DataSet dataSet)
        {
            var uri    = DocumentUri.From($"/{dataSet.Name}");
            var client = await IntegrationTestHelper.StartServerWithTextAsync(dataSet.Bicep, uri);

            // construct a parallel compilation
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));
            var lineStarts  = TextCoordinateConverter.GetLineStarts(dataSet.Bicep);
            var fixables    = compilation.GetSemanticModel().GetAllDiagnostics().OfType <IFixable>();

            foreach (IFixable fixable in fixables)
            {
                foreach (var span in GetOverlappingSpans(fixable.Span))
                {
                    CommandOrCodeActionContainer?quickFixes = await client.RequestCodeAction(new CodeActionParams
                    {
                        TextDocument = new TextDocumentIdentifier(uri),
                        Range        = span.ToRange(lineStarts)
                    });

                    // Assert.
                    quickFixes.Should().NotBeNull();

                    var quickFixList = quickFixes.ToList();
                    var bicepFixList = fixable.Fixes.ToList();

                    quickFixList.Should().HaveSameCount(bicepFixList);

                    for (int i = 0; i < quickFixList.Count; i++)
                    {
                        var quickFix = quickFixList[i];
                        var bicepFix = bicepFixList[i];

                        quickFix.IsCodeAction.Should().BeTrue();
                        quickFix.CodeAction.Kind.Should().Be(CodeActionKind.QuickFix);
                        quickFix.CodeAction.Title.Should().Be(bicepFix.Description);
                        quickFix.CodeAction.Edit.Changes.Should().ContainKey(uri);

                        var textEditList    = quickFix.CodeAction.Edit.Changes[uri].ToList();
                        var replacementList = bicepFix.Replacements.ToList();

                        for (int j = 0; j < textEditList.Count; j++)
                        {
                            var textEdit    = textEditList[j];
                            var replacement = replacementList[j];

                            textEdit.Range.Should().Be(replacement.ToRange(lineStarts));
                            textEdit.NewText.Should().Be(replacement.Text);
                        }
                    }
                }
            }
        }
Пример #26
0
        public void OutputTypeContextShouldReturnDeclarationTypeCompletions()
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(string.Empty));
            var provider    = new BicepCompletionProvider();

            var completions = provider.GetFilteredCompletions(compilation.GetEntrypointSemanticModel(), new BicepCompletionContext(BicepCompletionContextKind.OutputType));
            var declarationTypeCompletions = completions.Where(c => c.Kind == CompletionItemKind.Class).ToList();

            AssertExpectedDeclarationTypeCompletions(declarationTypeCompletions);

            completions.Where(c => c.Kind == CompletionItemKind.Snippet).Should().BeEmpty();
        }
        public void Create_ShouldReturnValidCompilation()
        {
            var provider = new BicepCompilationProvider(TestResourceTypeProvider.Create(), CreateEmptyFileResolver());

            var fileUri = DocumentUri.Parse($"/{DataSets.Parameters_LF.Name}.bicep");
            var context = provider.Create(fileUri, DataSets.Parameters_LF.Bicep);

            context.Compilation.Should().NotBeNull();
            context.Compilation.GetEntrypointSemanticModel().GetAllDiagnostics().Should().BeEmpty();
            context.LineStarts.Should().NotBeEmpty();
            context.LineStarts[0].Should().Be(0);
        }
Пример #28
0
        public void CommentShouldNotGiveAnyCompletions(string codeFragment)
        {
            var grouping    = SyntaxTreeGroupingFactory.CreateFromText(codeFragment);
            var compilation = new Compilation(TestResourceTypeProvider.Create(), grouping);
            var provider    = new BicepCompletionProvider(new FileResolver(), new SnippetsProvider());

            var offset = codeFragment.IndexOf('|');

            var completions = provider.GetFilteredCompletions(compilation, BicepCompletionContext.Create(compilation, offset));

            completions.Should().BeEmpty();
        }
Пример #29
0
        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(TestResourceTypeProvider.Create(), SyntaxTreeGroupingFactory.CreateForFiles(files, mainUri));

            var(success, diagnosticsByFile) = GetSuccessAndDiagnosticsByFile(compilation);
            diagnosticsByFile.Values.SelectMany(x => x).Should().BeEmpty();
            success.Should().BeTrue();
            GetTemplate(compilation).Should().NotBeEmpty();
        }
Пример #30
0
        public void NameBindingsShouldBeConsistent(DataSet dataSet)
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(dataSet.Bicep));

            var symbolReferences = GetSymbolReferences(compilation.ProgramSyntax);

            // just a sanity check
            symbolReferences.Should().AllBeAssignableTo <ISymbolReference>();

            var model = compilation.GetSemanticModel();

            foreach (SyntaxBase symbolReference in symbolReferences)
            {
                var symbol = model.GetSymbolInfo(symbolReference);
                symbol.Should().NotBeNull();

                if (dataSet.IsValid)
                {
                    // valid cases should not return error symbols for any symbol reference node
                    symbol.Should().NotBeOfType <UnassignableSymbol>();
                    symbol.Should().Match(s =>
                                          s is ParameterSymbol ||
                                          s is VariableSymbol ||
                                          s is ResourceSymbol ||
                                          s is OutputSymbol ||
                                          s is FunctionSymbol ||
                                          s is NamespaceSymbol);
                }
                else
                {
                    // invalid files may return errors
                    symbol.Should().Match(s =>
                                          s is UnassignableSymbol ||
                                          s is ParameterSymbol ||
                                          s is VariableSymbol ||
                                          s is ResourceSymbol ||
                                          s is OutputSymbol ||
                                          s is FunctionSymbol ||
                                          s is NamespaceSymbol);
                }

                var foundRefs = model.FindReferences(symbol !);

                // the returned references should contain the original ref that we used to find the symbol
                foundRefs.Should().Contain(symbolReference);

                // each ref should map to the same exact symbol
                foreach (SyntaxBase foundRef in foundRefs)
                {
                    model.GetSymbolInfo(foundRef).Should().BeSameAs(symbol);
                }
            }
        }