MinItems and MaxItems can be validated once again

The new hcldec dynamic block behavior no longer tried to validate
MinItems and MaxItems when the number of values is unknown.
This commit is contained in:
James Bardin 2021-04-15 17:17:36 -04:00
parent 59c8281378
commit 3e49c4b388
2 changed files with 21 additions and 21 deletions

View File

@ -101,15 +101,6 @@ func (b *Block) DecoderSpec() hcldec.Spec {
childSpec := blockS.Block.DecoderSpec() childSpec := blockS.Block.DecoderSpec()
// We can only validate 0 or 1 for MinItems, because a dynamic block
// may satisfy any number of min items while only having a single
// block in the config. We cannot validate MaxItems because a
// configuration may have any number of dynamic blocks.
minItems := 0
if blockS.MinItems > 1 {
minItems = 1
}
switch blockS.Nesting { switch blockS.Nesting {
case NestingSingle, NestingGroup: case NestingSingle, NestingGroup:
ret[name] = &hcldec.BlockSpec{ ret[name] = &hcldec.BlockSpec{
@ -134,13 +125,15 @@ func (b *Block) DecoderSpec() hcldec.Spec {
ret[name] = &hcldec.BlockTupleSpec{ ret[name] = &hcldec.BlockTupleSpec{
TypeName: name, TypeName: name,
Nested: childSpec, Nested: childSpec,
MinItems: minItems, MinItems: blockS.MinItems,
MaxItems: blockS.MaxItems,
} }
} else { } else {
ret[name] = &hcldec.BlockListSpec{ ret[name] = &hcldec.BlockListSpec{
TypeName: name, TypeName: name,
Nested: childSpec, Nested: childSpec,
MinItems: minItems, MinItems: blockS.MinItems,
MaxItems: blockS.MaxItems,
} }
} }
case NestingSet: case NestingSet:
@ -154,7 +147,8 @@ func (b *Block) DecoderSpec() hcldec.Spec {
ret[name] = &hcldec.BlockSetSpec{ ret[name] = &hcldec.BlockSetSpec{
TypeName: name, TypeName: name,
Nested: childSpec, Nested: childSpec,
MinItems: minItems, MinItems: blockS.MinItems,
MaxItems: blockS.MaxItems,
} }
case NestingMap: case NestingMap:
// We prefer to use a list where possible, since it makes our // We prefer to use a list where possible, since it makes our

View File

@ -344,15 +344,12 @@ func TestBlockDecoderSpec(t *testing.T) {
}, },
&hcl.Block{ &hcl.Block{
Type: "foo", Type: "foo",
Body: hcl.EmptyBody(), Body: unknownBody{hcl.EmptyBody()},
}, },
}, },
}), }),
cty.ObjectVal(map[string]cty.Value{ cty.ObjectVal(map[string]cty.Value{
"foo": cty.ListVal([]cty.Value{ "foo": cty.UnknownVal(cty.List(cty.EmptyObject)),
cty.EmptyObjectVal,
cty.EmptyObjectVal,
}),
}), }),
0, // max items cannot be validated during decode 0, // max items cannot be validated during decode
}, },
@ -372,14 +369,12 @@ func TestBlockDecoderSpec(t *testing.T) {
Blocks: hcl.Blocks{ Blocks: hcl.Blocks{
&hcl.Block{ &hcl.Block{
Type: "foo", Type: "foo",
Body: hcl.EmptyBody(), Body: unknownBody{hcl.EmptyBody()},
}, },
}, },
}), }),
cty.ObjectVal(map[string]cty.Value{ cty.ObjectVal(map[string]cty.Value{
"foo": cty.ListVal([]cty.Value{ "foo": cty.UnknownVal(cty.List(cty.EmptyObject)),
cty.EmptyObjectVal,
}),
}), }),
0, 0,
}, },
@ -401,6 +396,7 @@ func TestBlockDecoderSpec(t *testing.T) {
for name, test := range tests { for name, test := range tests {
t.Run(name, func(t *testing.T) { t.Run(name, func(t *testing.T) {
spec := test.Schema.DecoderSpec() spec := test.Schema.DecoderSpec()
got, diags := hcldec.Decode(test.TestBody, spec, nil) got, diags := hcldec.Decode(test.TestBody, spec, nil)
if len(diags) != test.DiagCount { if len(diags) != test.DiagCount {
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount) t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount)
@ -427,6 +423,16 @@ func TestBlockDecoderSpec(t *testing.T) {
} }
} }
// this satisfies hcldec.UnknownBody to simulate a dynamic block with an
// unknown number of values.
type unknownBody struct {
hcl.Body
}
func (b unknownBody) Unknown() bool {
return true
}
func TestAttributeDecoderSpec(t *testing.T) { func TestAttributeDecoderSpec(t *testing.T) {
tests := map[string]struct { tests := map[string]struct {
Schema *Attribute Schema *Attribute