public void Casing_issues_are_corrected() { var bicepFile = @" resource resA 'My.Rp/resA@2020-01-01' = { name: 'resA' properties: { lowerCaseProp: 'abc' camelcaseprop: 'def' 'lowerCaseQuoted=+.Prop': 'ghi' 'camelcasequoted=+.prop': 'jkl' lowerCaseEnumProp: 'MyEnum' pascalCaseEnumProp: 'myenum' lowerCaseEnumUnionProp: 'MyEnum' pascalCaseEnumUnionProp: 'myenum' } } output myObj object = { lowerCaseProp: resA.properties.lowerCaseProp camelcaseprop: resA.properties.camelcaseprop } "; var typeDefinition = TestTypeHelper.CreateCustomResourceType("My.Rp/resA", "2020-01-01", TypeSymbolValidationFlags.WarnOnTypeMismatch, new TypeProperty("lowercaseprop", LanguageConstants.String), new TypeProperty("camelCaseProp", LanguageConstants.String), new TypeProperty("lowercasequoted=+.prop", LanguageConstants.String), new TypeProperty("camelCaseQuoted=+.Prop", LanguageConstants.String), new TypeProperty("lowerCaseEnumProp", new StringLiteralType("myenum")), new TypeProperty("pascalCaseEnumProp", new StringLiteralType("MyEnum")), new TypeProperty("lowerCaseEnumUnionProp", TypeHelper.CreateTypeUnion(new StringLiteralType("myenum"), new StringLiteralType("blahblah"))), new TypeProperty("pascalCaseEnumUnionProp", TypeHelper.CreateTypeUnion(new StringLiteralType("MyEnum"), new StringLiteralType("BlahBlah")))); var typeLoader = TestTypeHelper.CreateAzResourceTypeLoaderWithTypes(typeDefinition.AsEnumerable()); var(_, _, compilation) = CompilationHelper.Compile(typeLoader, ("main.bicep", bicepFile)); var rewriter = new TypeCasingFixerRewriter(compilation.GetEntrypointSemanticModel()); var newProgramSyntax = rewriter.Rewrite(compilation.SourceFileGrouping.EntryPoint.ProgramSyntax); PrintHelper.PrintAndCheckForParseErrors(newProgramSyntax).Should().Be( @"resource resA 'My.Rp/resA@2020-01-01' = { name: 'resA' properties: { lowercaseprop: 'abc' camelCaseProp: 'def' 'lowercasequoted=+.prop': 'ghi' 'camelCaseQuoted=+.Prop': 'jkl' lowerCaseEnumProp: 'myenum' pascalCaseEnumProp: 'MyEnum' lowerCaseEnumUnionProp: 'myenum' pascalCaseEnumUnionProp: 'MyEnum' } } output myObj object = { lowerCaseProp: resA.properties.lowercaseprop camelcaseprop: resA.properties.camelCaseProp }"); }
public void Errors_are_raised_for_existing_resources_at_invalid_scopes() { var typeReference = ResourceTypeReference.Parse("My.Rp/myResource@2020-01-01"); var typeLoader = TestTypeHelper.CreateAzResourceTypeLoaderWithTypes(new [] { new ResourceTypeComponents(typeReference, ResourceScope.ResourceGroup, new ObjectType(typeReference.FormatName(), TypeSymbolValidationFlags.Default, new [] { new TypeProperty("name", LanguageConstants.String, TypePropertyFlags.DeployTimeConstant, "name property"), }, null)) }); // explicitly pass an invalid scope var(_, diags, _) = CompilationHelper.Compile(typeLoader, ("main.bicep", @" resource resourceA 'My.Rp/myResource@2020-01-01' existing = { name: 'resourceA' scope: subscription() } ")); diags.Should().HaveDiagnostics(new[] {
public void Readonly_properties_are_removed() { var bicepFile = @" resource resA 'My.Rp/resA@2020-01-01' = { name: 'resA' properties: { readOnlyProp: 'abc' readWriteProp: 'def' writeOnlyProp: 'ghi' } } output myObj object = { readOnlyProp: resA.properties.readOnlyProp readWriteProp: resA.properties.readWriteProp } "; var typeDefinition = TestTypeHelper.CreateCustomResourceType("My.Rp/resA", "2020-01-01", TypeSymbolValidationFlags.WarnOnTypeMismatch, new TypeProperty("readOnlyProp", LanguageConstants.String, TypePropertyFlags.ReadOnly), new TypeProperty("readWriteProp", LanguageConstants.String, TypePropertyFlags.None), new TypeProperty("writeOnlyProp", LanguageConstants.String, TypePropertyFlags.WriteOnly)); var typeLoader = TestTypeHelper.CreateAzResourceTypeLoaderWithTypes(typeDefinition.AsEnumerable()); var(_, _, compilation) = CompilationHelper.Compile(typeLoader, ("main.bicep", bicepFile)); var rewriter = new ReadOnlyPropertyRemovalRewriter(compilation.GetEntrypointSemanticModel()); var newProgramSyntax = rewriter.Rewrite(compilation.SourceFileGrouping.EntryPoint.ProgramSyntax); PrintHelper.PrintAndCheckForParseErrors(newProgramSyntax).Should().Be( @"resource resA 'My.Rp/resA@2020-01-01' = { name: 'resA' properties: { readWriteProp: 'def' writeOnlyProp: 'ghi' } } output myObj object = { readOnlyProp: resA.properties.readOnlyProp readWriteProp: resA.properties.readWriteProp }"); }
public void Existing_resources_can_be_referenced_at_other_scopes() { var typeReference = ResourceTypeReference.Parse("My.Rp/myResource@2020-01-01"); var typeLoader = TestTypeHelper.CreateAzResourceTypeLoaderWithTypes(new [] { new ResourceTypeComponents(typeReference, ResourceScope.ResourceGroup, new ObjectType(typeReference.FormatName(), TypeSymbolValidationFlags.Default, new [] { new TypeProperty("name", LanguageConstants.String, TypePropertyFlags.DeployTimeConstant, "name property"), new TypeProperty("kind", LanguageConstants.String, TypePropertyFlags.ReadOnly, "kind property"), }, null)) }); // explicitly pass a valid scope var(template, _, _) = CompilationHelper.Compile(typeLoader, ("main.bicep", @" resource resourceA 'My.Rp/myResource@2020-01-01' existing = { name: 'resourceA' scope: resourceGroup() } output resourceARef string = resourceA.kind ")); using (new AssertionScope()) { template.Should().HaveValueAtPath("$.outputs['resourceARef'].value", "[reference(resourceId('My.Rp/myResource', 'resourceA'), '2020-01-01', 'full').kind]"); } // use a valid targetScope without setting the scope property (template, _, _) = CompilationHelper.Compile(typeLoader, ("main.bicep", @" targetScope = 'resourceGroup' resource resourceA 'My.Rp/myResource@2020-01-01' existing = { name: 'resourceA' } output resourceARef string = resourceA.kind ")); using (new AssertionScope()) { template.Should().HaveValueAtPath("$.outputs['resourceARef'].value", "[reference(resourceId('My.Rp/myResource', 'resourceA'), '2020-01-01', 'full').kind]"); } }
public void Nested_casing_issues_take_multiple_passes_to_correct() { var bicepFile = @" resource resA 'My.Rp/resA@2020-01-01' = { name: 'resA' properties: { lowerCaseObj: { lowerCaseStr: 'test' } } } output myObj object = { lowerCaseProp: resA.properties.lowerCaseObj.lowerCaseStr } "; var typeDefinition = TestTypeHelper.CreateCustomResourceType("My.Rp/resA", "2020-01-01", TypeSymbolValidationFlags.WarnOnTypeMismatch, new TypeProperty("lowercaseobj", new ObjectType("lowercaseobj", TypeSymbolValidationFlags.Default, new [] { new TypeProperty("lowercasestr", LanguageConstants.String) }, null))); var typeLoader = TestTypeHelper.CreateAzResourceTypeLoaderWithTypes(typeDefinition.AsEnumerable()); var(_, _, compilation) = CompilationHelper.Compile(typeLoader, ("main.bicep", bicepFile)); var rewriter = new TypeCasingFixerRewriter(compilation.GetEntrypointSemanticModel()); var newProgramSyntax = rewriter.Rewrite(compilation.SourceFileGrouping.EntryPoint.ProgramSyntax); var firstPassBicepFile = PrintHelper.PrintAndCheckForParseErrors(newProgramSyntax); firstPassBicepFile.Should().Be( @"resource resA 'My.Rp/resA@2020-01-01' = { name: 'resA' properties: { lowercaseobj: { lowerCaseStr: 'test' } } } output myObj object = { lowerCaseProp: resA.properties.lowercaseobj.lowerCaseStr }"); (_, _, compilation) = CompilationHelper.Compile(typeLoader, ("main.bicep", firstPassBicepFile)); rewriter = new TypeCasingFixerRewriter(compilation.GetEntrypointSemanticModel()); newProgramSyntax = rewriter.Rewrite(compilation.SourceFileGrouping.EntryPoint.ProgramSyntax); PrintHelper.PrintAndCheckForParseErrors(newProgramSyntax).Should().Be( @"resource resA 'My.Rp/resA@2020-01-01' = { name: 'resA' properties: { lowercaseobj: { lowercasestr: 'test' } } } output myObj object = { lowerCaseProp: resA.properties.lowercaseobj.lowercasestr }"); }