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 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 [] {
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(); }
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); } }
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(); } }
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 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); }
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)); }
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[] {
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); }
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(); }
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(); } }
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(); }
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)); }
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)); }
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(); }
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(); }
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)); }
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 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); }
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)); }
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 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 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); }
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); } } } } }
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); }
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(); }
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(); }
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); } } }