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(); }
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(); }
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); }); }
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(); }
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); }
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); }
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); }); }
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); }
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"); }); }
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}"); } }