| // Copyright IBM Corp. 2014, 2026 | |
| // SPDX-License-Identifier: BUSL-1.1 | |
| package blocktoattr | |
| import ( | |
| "testing" | |
| "github.com/hashicorp/hcl/v2" | |
| "github.com/hashicorp/hcl/v2/hcldec" | |
| "github.com/hashicorp/hcl/v2/hclsyntax" | |
| "github.com/hashicorp/terraform/internal/configs/configschema" | |
| "github.com/zclconf/go-cty/cty" | |
| ) | |
| func ambiguousNestedBlock(nesting int) *configschema.NestedBlock { | |
| ret := &configschema.NestedBlock{ | |
| Nesting: configschema.NestingList, | |
| Block: configschema.Block{ | |
| Attributes: map[string]*configschema.Attribute{ | |
| "a": {Type: cty.String, Required: true}, | |
| "b": {Type: cty.String, Optional: true}, | |
| }, | |
| }, | |
| } | |
| if nesting > 0 { | |
| ret.BlockTypes = map[string]*configschema.NestedBlock{ | |
| "nested0": ambiguousNestedBlock(nesting - 1), | |
| "nested1": ambiguousNestedBlock(nesting - 1), | |
| "nested2": ambiguousNestedBlock(nesting - 1), | |
| "nested3": ambiguousNestedBlock(nesting - 1), | |
| "nested4": ambiguousNestedBlock(nesting - 1), | |
| "nested5": ambiguousNestedBlock(nesting - 1), | |
| "nested6": ambiguousNestedBlock(nesting - 1), | |
| "nested7": ambiguousNestedBlock(nesting - 1), | |
| "nested8": ambiguousNestedBlock(nesting - 1), | |
| "nested9": ambiguousNestedBlock(nesting - 1), | |
| } | |
| } | |
| return ret | |
| } | |
| func schemaWithAmbiguousNestedBlock(nesting int) *configschema.Block { | |
| return &configschema.Block{ | |
| BlockTypes: map[string]*configschema.NestedBlock{ | |
| "maybe_block": ambiguousNestedBlock(nesting), | |
| }, | |
| } | |
| } | |
| const configForFixupBlockAttrsBenchmark = ` | |
| maybe_block { | |
| a = "hello" | |
| b = "world" | |
| nested0 { | |
| a = "the" | |
| nested1 { | |
| a = "deeper" | |
| nested2 { | |
| a = "we" | |
| nested3 { | |
| a = "go" | |
| b = "inside" | |
| } | |
| } | |
| } | |
| } | |
| } | |
| ` | |
| func configBodyForFixupBlockAttrsBenchmark() hcl.Body { | |
| f, diags := hclsyntax.ParseConfig([]byte(configForFixupBlockAttrsBenchmark), "", hcl.Pos{Line: 1, Column: 1}) | |
| if diags.HasErrors() { | |
| panic("test configuration is invalid") | |
| } | |
| return f.Body | |
| } | |
| func BenchmarkFixUpBlockAttrs(b *testing.B) { | |
| for i := 0; i < b.N; i++ { | |
| b.StopTimer() | |
| body := configBodyForFixupBlockAttrsBenchmark() | |
| schema := schemaWithAmbiguousNestedBlock(5) | |
| b.StartTimer() | |
| spec := schema.DecoderSpec() | |
| fixedBody := FixUpBlockAttrs(body, schema) | |
| val, diags := hcldec.Decode(fixedBody, spec, nil) | |
| if diags.HasErrors() { | |
| b.Fatal("diagnostics during decoding", diags) | |
| } | |
| if !val.Type().IsObjectType() { | |
| b.Fatal("result is not an object") | |
| } | |
| blockVal := val.GetAttr("maybe_block") | |
| if !blockVal.Type().IsListType() || blockVal.LengthInt() != 1 { | |
| b.Fatal("result has wrong value for 'maybe_block'") | |
| } | |
| } | |
| } |