예제 #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 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");
            });
        }
        public void CompletionsForOneLinerParameterDefaultValueShouldIncludeFunctionsValidInDefaultValues()
        {
            var grouping    = SyntaxTreeGroupingFactory.CreateFromText(@"param p string = ");
            var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping);

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

            var provider    = new BicepCompletionProvider(new FileResolver(), new SnippetsProvider(), new TelemetryProvider(Server));
            var completions = provider.GetFilteredCompletions(
                compilation,
                BicepCompletionContext.Create(compilation, offset)).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 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");
            });
        }
        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);
            });
        }
예제 #6
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 !];
        public void CommentShouldNotGiveAnyCompletions(string codeFragment)
        {
            var grouping    = SyntaxTreeGroupingFactory.CreateFromText(codeFragment);
            var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping);
            var provider    = new BicepCompletionProvider(new FileResolver(), new SnippetsProvider(), new TelemetryProvider(Server));

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

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

            completions.Should().BeEmpty();
        }
예제 #8
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 DeclaringSymbolWithFunctionNameShouldHideTheFunctionCompletion()
        {
            var grouping = SyntaxTreeGroupingFactory.CreateFromText(@"
param concat string
var resourceGroup = true
resource base64 'Microsoft.Foo/foos@2020-09-01' = {
  name: 'foo'
}
output length int = 
");
            var offset   = grouping.EntryPoint.ProgramSyntax.Declarations.OfType <OutputDeclarationSyntax>().Single().Value.Span.Position;

            var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping);
            var provider    = new BicepCompletionProvider(new FileResolver(), new SnippetsProvider(), new TelemetryProvider(Server));
            var context     = BicepCompletionContext.Create(compilation, offset);
            var completions = provider.GetFilteredCompletions(compilation, context).ToList();

            AssertExpectedFunctions(completions, expectParamDefaultFunctions: false, new[] { "sys.concat", "az.resourceGroup", "sys.base64" });

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

            const string expectedVariable   = "resourceGroup";
            var          variableCompletion = completions.Single(c => c.Kind == SymbolKind.Variable.ToCompletionItemKind());

            variableCompletion.Label.Should().Be(expectedVariable);
            variableCompletion.Kind.Should().Be(CompletionItemKind.Variable);
            variableCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            variableCompletion.TextEdit !.TextEdit !.NewText.Should().Be(expectedVariable);
            variableCompletion.CommitCharacters.Should().BeNull();
            variableCompletion.Detail.Should().Be(expectedVariable);

            const string expectedResource   = "base64";
            var          resourceCompletion = completions.Single(c => c.Kind == SymbolKind.Resource.ToCompletionItemKind());

            resourceCompletion.Label.Should().Be(expectedResource);
            resourceCompletion.Kind.Should().Be(CompletionItemKind.Interface);
            resourceCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            resourceCompletion.TextEdit !.TextEdit !.NewText.Should().Be(expectedResource);
            resourceCompletion.CommitCharacters.Should().BeEquivalentTo(new [] { ":", });
            resourceCompletion.Detail.Should().Be(expectedResource);

            const string expectedParam   = "concat";
            var          paramCompletion = completions.Single(c => c.Kind == SymbolKind.Parameter.ToCompletionItemKind());

            paramCompletion.Label.Should().Be(expectedParam);
            paramCompletion.Kind.Should().Be(CompletionItemKind.Field);
            paramCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            paramCompletion.TextEdit !.TextEdit !.NewText.Should().Be(expectedParam);
            paramCompletion.CommitCharacters.Should().BeNull();
            paramCompletion.Detail.Should().Be(expectedParam);
        }
예제 #10
0
        public void DeclaringSymbolWithFunctionNameShouldHideTheFunctionCompletion()
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(@"
param concat string
var resourceGroup = true
resource base64 'Microsoft.Foo/foos@2020-09-01' = {
  name: 'foo'
}
output length int = 42
"));

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

            var provider    = new BicepCompletionProvider();
            var completions = provider.GetFilteredCompletions(compilation.GetSemanticModel(), new BicepCompletionContext(BicepCompletionContextKind.None)).ToList();

            AssertExpectedFunctions(completions, new[] { "concat", "resourceGroup", "base64" });

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

            const string expectedVariable   = "resourceGroup";
            var          variableCompletion = completions.Single(c => c.Kind == SymbolKind.Variable.ToCompletionItemKind());

            variableCompletion.Label.Should().Be(expectedVariable);
            variableCompletion.Kind.Should().Be(CompletionItemKind.Variable);
            variableCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            variableCompletion.InsertText.Should().Be(expectedVariable);
            variableCompletion.CommitCharacters.Should().BeNull();
            variableCompletion.Detail.Should().Be(expectedVariable);

            const string expectedResource   = "base64";
            var          resourceCompletion = completions.Single(c => c.Kind == SymbolKind.Resource.ToCompletionItemKind());

            resourceCompletion.Label.Should().Be(expectedResource);
            resourceCompletion.Kind.Should().Be(CompletionItemKind.Interface);
            resourceCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            resourceCompletion.InsertText.Should().Be(expectedResource);
            resourceCompletion.CommitCharacters.Should().BeNull();
            resourceCompletion.Detail.Should().Be(expectedResource);

            const string expectedParam   = "concat";
            var          paramCompletion = completions.Single(c => c.Kind == SymbolKind.Parameter.ToCompletionItemKind());

            paramCompletion.Label.Should().Be(expectedParam);
            paramCompletion.Kind.Should().Be(CompletionItemKind.Field);
            paramCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            paramCompletion.InsertText.Should().Be(expectedParam);
            paramCompletion.CommitCharacters.Should().BeNull();
            paramCompletion.Detail.Should().Be(expectedParam);
        }
예제 #11
0
        public void NonDeclarationContextShouldIncludeDeclaredSymbols()
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(@"
param p string
var v = true
resource r 'Microsoft.Foo/foos@2020-09-01' = {
  name: 'foo'
}
output o int = 42
"));

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

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

            AssertExpectedFunctions(completions, expectParamDefaultFunctions: false);

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

            const string expectedVariable   = "v";
            var          variableCompletion = completions.Single(c => c.Kind == SymbolKind.Variable.ToCompletionItemKind());

            variableCompletion.Label.Should().Be(expectedVariable);
            variableCompletion.Kind.Should().Be(CompletionItemKind.Variable);
            variableCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            variableCompletion.InsertText.Should().Be(expectedVariable);
            variableCompletion.CommitCharacters.Should().BeNull();
            variableCompletion.Detail.Should().Be(expectedVariable);

            const string expectedResource   = "r";
            var          resourceCompletion = completions.Single(c => c.Kind == SymbolKind.Resource.ToCompletionItemKind());

            resourceCompletion.Label.Should().Be(expectedResource);
            resourceCompletion.Kind.Should().Be(CompletionItemKind.Interface);
            resourceCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            resourceCompletion.InsertText.Should().Be(expectedResource);
            resourceCompletion.CommitCharacters.Should().BeNull();
            resourceCompletion.Detail.Should().Be(expectedResource);

            const string expectedParam   = "p";
            var          paramCompletion = completions.Single(c => c.Kind == SymbolKind.Parameter.ToCompletionItemKind());

            paramCompletion.Label.Should().Be(expectedParam);
            paramCompletion.Kind.Should().Be(CompletionItemKind.Field);
            paramCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            paramCompletion.InsertText.Should().Be(expectedParam);
            paramCompletion.CommitCharacters.Should().BeNull();
            paramCompletion.Detail.Should().Be(expectedParam);
        }
        public void OutputTypeContextShouldReturnDeclarationTypeCompletions()
        {
            var grouping    = SyntaxTreeGroupingFactory.CreateFromText("output test ");
            var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping);
            var provider    = new BicepCompletionProvider(new FileResolver(), new SnippetsProvider(), new TelemetryProvider(Server));

            var offset = grouping.EntryPoint.ProgramSyntax.Declarations.OfType <OutputDeclarationSyntax>().Single().Type.Span.Position;

            var completions = provider.GetFilteredCompletions(compilation, BicepCompletionContext.Create(compilation, offset));
            var declarationTypeCompletions = completions.Where(c => c.Kind == CompletionItemKind.Class).ToList();

            AssertExpectedDeclarationTypeCompletions(declarationTypeCompletions);

            completions.Where(c => c.Kind == CompletionItemKind.Snippet).Should().BeEmpty();
        }
        public void VerifyParameterTypeCompletionWithPrecedingComment()
        {
            var grouping    = SyntaxTreeGroupingFactory.CreateFromText("/*test*/param foo ");
            var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping);
            var provider    = new BicepCompletionProvider(new FileResolver(), new SnippetsProvider(), new TelemetryProvider(Server));

            var offset = grouping.EntryPoint.ProgramSyntax.Declarations.OfType <ParameterDeclarationSyntax>().Single().Type.Span.Position;

            var completions = provider.GetFilteredCompletions(compilation, BicepCompletionContext.Create(compilation, offset));
            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.TextEdit !.TextEdit !.NewText.Should().Be("object");
                c.TextEdit.TextEdit.Range.Start.Line.Should().Be(0);
                c.TextEdit.TextEdit.Range.Start.Character.Should().Be(18);
                c.Detail.Should().Be("Secure object");
                c.AdditionalTextEdits !.Count().Should().Be(1);
                c.AdditionalTextEdits !.ElementAt(0).NewText.Should().Be("@secure()\n");
                c.AdditionalTextEdits !.ElementAt(0).Range.Start.Line.Should().Be(0);
                c.AdditionalTextEdits !.ElementAt(0).Range.Start.Character.Should().Be(8);
                c.AdditionalTextEdits !.ElementAt(0).Range.End.Line.Should().Be(0);
                c.AdditionalTextEdits !.ElementAt(0).Range.End.Character.Should().Be(8);
            },
                c =>
            {
                c.Label.Should().Be("secureString");
                c.Kind.Should().Be(CompletionItemKind.Snippet);
                c.InsertTextFormat.Should().Be(InsertTextFormat.Snippet);
                c.TextEdit !.TextEdit !.NewText.Should().Be("string");
                c.TextEdit.TextEdit.Range.Start.Line.Should().Be(0);
                c.TextEdit.TextEdit.Range.Start.Character.Should().Be(18);
                c.Detail.Should().Be("Secure string");
                c.AdditionalTextEdits !.Count().Should().Be(1);
                c.AdditionalTextEdits !.ElementAt(0).NewText.Should().Be("@secure()\n");
                c.AdditionalTextEdits !.ElementAt(0).Range.Start.Line.Should().Be(0);
                c.AdditionalTextEdits !.ElementAt(0).Range.Start.Character.Should().Be(8);
                c.AdditionalTextEdits !.ElementAt(0).Range.End.Line.Should().Be(0);
                c.AdditionalTextEdits !.ElementAt(0).Range.End.Character.Should().Be(8);
            });
        }
예제 #14
0
        public void NonDeclarationContextInEmptyFileShouldReturnFunctionCompletions()
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(string.Empty));

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

            var provider = new BicepCompletionProvider();

            var completions = provider.GetFilteredCompletions(compilation.GetSemanticModel(), new BicepCompletionContext(BicepCompletionContextKind.None)).ToList();

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

            AssertExpectedFunctions(completions);
        }
        public void NonDeclarationContextShouldIncludeDeclaredSymbols()
        {
            var grouping    = SyntaxTreeGroupingFactory.CreateFromText(@"
param p string
var v = 
resource r 'Microsoft.Foo/foos@2020-09-01' = {
  name: 'foo'
}
output o int = 42
");
            var offset      = grouping.EntryPoint.ProgramSyntax.Declarations.OfType <VariableDeclarationSyntax>().Single().Value.Span.Position;
            var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping);

            var provider    = new BicepCompletionProvider(new FileResolver(), new SnippetsProvider(), new TelemetryProvider(Server));
            var context     = BicepCompletionContext.Create(compilation, offset);
            var completions = provider.GetFilteredCompletions(compilation, context).ToList();

            AssertExpectedFunctions(completions, expectParamDefaultFunctions: false);

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

            // the variable won't appear in completions because we are not suggesting cycles
            completions.Where(c => c.Kind == SymbolKind.Variable.ToCompletionItemKind()).Should().BeEmpty();

            const string expectedResource   = "r";
            var          resourceCompletion = completions.Single(c => c.Kind == SymbolKind.Resource.ToCompletionItemKind());

            resourceCompletion.Label.Should().Be(expectedResource);
            resourceCompletion.Kind.Should().Be(CompletionItemKind.Interface);
            resourceCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            resourceCompletion.TextEdit !.TextEdit !.NewText.Should().Be(expectedResource);
            resourceCompletion.CommitCharacters.Should().BeEquivalentTo(new[] { ":", });
            resourceCompletion.Detail.Should().Be(expectedResource);

            const string expectedParam   = "p";
            var          paramCompletion = completions.Single(c => c.Kind == SymbolKind.Parameter.ToCompletionItemKind());

            paramCompletion.Label.Should().Be(expectedParam);
            paramCompletion.Kind.Should().Be(CompletionItemKind.Field);
            paramCompletion.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
            paramCompletion.TextEdit !.TextEdit !.NewText.Should().Be(expectedParam);
            paramCompletion.CommitCharacters.Should().BeNull();
            paramCompletion.Detail.Should().Be(expectedParam);
        }
예제 #16
0
        public void DeclarationSnippetsShouldBeValid()
        {
            var grouping    = SyntaxTreeGroupingFactory.CreateFromText(string.Empty);
            var compilation = new Compilation(TestResourceTypeProvider.Create(), grouping);

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

            ResourceSnippetsProvider resourceSnippetsProvider = new ResourceSnippetsProvider();

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

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

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

            IEnumerable <ResourceSnippet> resourceSnippets = resourceSnippetsProvider.GetResourceSnippets();

            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) || resourceSnippets.Any(rs => rs.Name == 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" },
                ["Kubernetes Service Cluster"] = new[] { "aksCluster", "1.5", "prefix", "2", "Standard_All", "userName", "keyData", "appId", "test" },
                ["Application Security Group"] = new[] { "myApplicationSecurityGroup" },
                ["Automation Account"]         = new[] { "myAutomationAccount", "Basic" },
                ["Availability Set"]           = new[] { "availabilitySet", "availabilitySet" },
                ["Container Group"]            = new[] { "myContainerGroup", "container", "image", "80", "1", "4", "Linux", "TCP", "80" },
                ["Container Registry"]         = new[] { "myContainerRegistry", "Basic", "true" },
                ["Cosmos DB Database Account"] = new[] { "myCosmosDBAccount", "MongoDB", "session", "1", "5", "location", "0", "filter", "false", "EnableTable" },
                ["Data Lake Store Account"]    = new[] { "myDataLakeStore", "Consumption", "Enabled" },
                ["DNS Zone"]          = new[] { "dnsZone" },
                ["Public IP Address"] = new[] { "192.168.1.10", "192.168.1.10", "dnsName" },
                ["Public IP Prefix"]  = new[] { "publicIpPrefix", "28" }
            };

            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 !];
        public void DeclarationContextShouldReturnKeywordCompletions()
        {
            var grouping    = SyntaxTreeGroupingFactory.CreateFromText(string.Empty);
            var compilation = new Compilation(TestTypeHelper.CreateEmptyProvider(), grouping);

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

            var provider = new BicepCompletionProvider(new FileResolver(), new SnippetsProvider(), new TelemetryProvider(Server));

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

            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().BeNull();
                c.Detail.Should().Be("Module keyword");
                c.TextEdit !.TextEdit !.NewText.Should().Be("module");
            },
                c =>
            {
                c.Label.Should().Be("output");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().BeNull();
                c.Detail.Should().Be("Output keyword");
                c.TextEdit !.TextEdit !.NewText.Should().Be("output");
            },
                c =>
            {
                c.Label.Should().Be("param");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().BeNull();
                c.Detail.Should().Be("Parameter keyword");
                c.TextEdit !.TextEdit !.NewText.Should().Be("param");
            },
                c =>
            {
                c.Label.Should().Be("resource");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().BeNull();
                c.Detail.Should().Be("Resource keyword");
                c.TextEdit !.TextEdit !.NewText.Should().Be("resource");
            },
                c =>
            {
                c.Label.Should().Be("targetScope");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().BeNull();
                c.Detail.Should().Be("Target Scope keyword");
                c.TextEdit !.TextEdit !.NewText.Should().Be("targetScope");
            },
                c =>
            {
                c.Label.Should().Be("var");
                c.Kind.Should().Be(CompletionItemKind.Keyword);
                c.InsertTextFormat.Should().Be(InsertTextFormat.PlainText);
                c.InsertText.Should().BeNull();
                c.Detail.Should().Be("Variable keyword");
                c.TextEdit !.TextEdit !.NewText.Should().Be("var");
            });
        }
예제 #18
0
        public void DeclarationSnippetsShouldBeValid()
        {
            var compilation = new Compilation(TestResourceTypeProvider.Create(), SyntaxFactory.CreateFromText(string.Empty));

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

            var provider = new BicepCompletionProvider();

            var completions = provider.GetFilteredCompletions(compilation.GetSemanticModel(), new BicepCompletionContext(BicepCompletionContextKind.Declaration));

            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.ToDictionary(c => c.Detail);

            var replacementsByDetail = new Dictionary <string, IList <string> >
            {
                ["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.InsertText);

                // 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];
                var replaced     = snippet.Format((s, placeholder) => placeholder.Index >= 0 && placeholder.Index < replacements.Count
                    ? replacements[placeholder.Index]
                    : string.Empty);

                var parser      = new Parser(replaced);
                var declaration = parser.Declaration();

                declaration.Should().BeAssignableTo <IDeclarationSyntax>($"because the snippet for '{detail}' failed to parse after replacements:\n{replaced}");
            }
        }