diff --git a/src/Bicep.Cli.IntegrationTests/BuildParamsCommandTests.cs b/src/Bicep.Cli.IntegrationTests/BuildParamsCommandTests.cs index 66b6fc1be1d..07fec39c690 100644 --- a/src/Bicep.Cli.IntegrationTests/BuildParamsCommandTests.cs +++ b/src/Bicep.Cli.IntegrationTests/BuildParamsCommandTests.cs @@ -640,5 +640,67 @@ param intParam int File.Exists(Path.Combine(bicepOutputPath, outputFile)).Should().Be(true, f); } } + + [TestMethod] + public async Task BuildParams_Extends_InvalidType_ThrowsError() + { + var outputPath = FileHelper.GetUniqueTestOutputPath(TestContext); + FileHelper.SaveResultFile(TestContext, "main.bicep", @" + param tag string + ", outputPath); + FileHelper.SaveResultFile(TestContext, "base.bicepparam", @" + using none + param tag = 42 + ", outputPath); + var inputFile = FileHelper.SaveResultFile(TestContext, "main.bicepparam", @" + using 'main.bicep' + extends 'base.bicepparam' + ", outputPath); + + var expectedOutputFile = FileHelper.GetResultFilePath(TestContext, "main.json", outputPath); + File.Exists(expectedOutputFile).Should().BeFalse(); + + var (output, error, result) = await Bicep(["build-params", inputFile]); + + File.Exists(expectedOutputFile).Should().BeFalse(); + + output.Should().BeEmpty(); + error.Should().Contain("Error BCP033: Expected a value of type \"string\" but the provided value is of type \"42\"."); + result.Should().Be(1); + } + + [TestMethod] + public async Task BuildParams_Extends_Multiple_InvalidType_ThrowsMultipleErrors() + { + var outputPath = FileHelper.GetUniqueTestOutputPath(TestContext); + FileHelper.SaveResultFile(TestContext, "main.bicep", @" + param myString string + param myInt int + param myBool bool + ", outputPath); + FileHelper.SaveResultFile(TestContext, "base.bicepparam", @" + using none + param myInt = '42' + param myString = {} + param myBool = [] + ", outputPath); + var inputFile = FileHelper.SaveResultFile(TestContext, "main.bicepparam", @" + using './main.bicep' + extends 'base.bicepparam' + ", outputPath); + + var expectedOutputFile = FileHelper.GetResultFilePath(TestContext, "main.json", outputPath); + File.Exists(expectedOutputFile).Should().BeFalse(); + + var (output, error, result) = await Bicep(["build-params", inputFile]); + + File.Exists(expectedOutputFile).Should().BeFalse(); + + output.Should().BeEmpty(); + error.Should().Contain("Error BCP033: Expected a value of type \"int\" but the provided value is of type \"'42'\"."); + error.Should().Contain("Error BCP033: Expected a value of type \"string\" but the provided value is of type \"object\"."); + error.Should().Contain("Error BCP033: Expected a value of type \"bool\" but the provided value is of type \"\"."); + result.Should().Be(1); + } } } diff --git a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs index 5cc339ad11e..9ef28474f55 100644 --- a/src/Bicep.Core.IntegrationTests/ScenarioTests.cs +++ b/src/Bicep.Core.IntegrationTests/ScenarioTests.cs @@ -7014,7 +7014,7 @@ public void DependsOn_order_is_deterministic_for_hierarchical_resource_symbolic_ } tenantId: '00000000-0000-0000-0000-000000000000' } - + resource secret 'secrets' = { name: 'secret' properties: {} @@ -7031,7 +7031,7 @@ public void DependsOn_order_is_deterministic_for_hierarchical_resource_symbolic_ } tenantId: '00000000-0000-0000-0000-000000000000' } - + resource secret 'secrets' = { name: 'secret' properties: {} @@ -7067,7 +7067,7 @@ public void DependsOn_on_existing_resource_triggers_languageVersion_2() module empty 'empty.bicep' = { name: 'foo' } - + resource sa 'Microsoft.Storage/storageAccounts@2023-05-01' existing = { name: 'storage' dependsOn: [ diff --git a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs index 43bf65a5485..7c3155d0ccf 100644 --- a/src/Bicep.Core/Emit/EmitLimitationCalculator.cs +++ b/src/Bicep.Core/Emit/EmitLimitationCalculator.cs @@ -11,6 +11,7 @@ using Bicep.Core.Navigation; using Bicep.Core.Semantics; using Bicep.Core.Semantics.Metadata; +using Bicep.Core.SourceGraph; using Bicep.Core.Syntax; using Bicep.Core.Syntax.Visitors; using Bicep.Core.Text; @@ -666,6 +667,18 @@ private static ImmutableDictionary sourceFile is BicepFile); + if (bicepFile is not null) + { + var paramDefinitionFromBicepFile = model.ModelLookup.GetSemanticModel(bicepFile).Parameters.FirstOrDefault(e => e.Key == symbol.Name); + + if (paramDefinitionFromBicepFile.Value is not null && !TypeValidator.AreTypesAssignable(paramDefinitionFromBicepFile.Value.TypeReference.Type, symbol.Type)) + { + diagnostics.WriteMultiple(DiagnosticBuilder.ForPosition(symbol.NameSource).ExpectedValueTypeMismatch(false, paramDefinitionFromBicepFile.Value.TypeReference.Type, symbol.Type)); + } + } + if (referencedValueHasError) { erroredSymbols.Add(symbol);