From 3e49c4b388ad6ffdcdcde7203b75a6a88a8707c6 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Thu, 15 Apr 2021 17:17:36 -0400 Subject: [PATCH] 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. --- configs/configschema/decoder_spec.go | 18 ++++++----------- configs/configschema/decoder_spec_test.go | 24 ++++++++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/configs/configschema/decoder_spec.go b/configs/configschema/decoder_spec.go index 41a3fc497..333274503 100644 --- a/configs/configschema/decoder_spec.go +++ b/configs/configschema/decoder_spec.go @@ -101,15 +101,6 @@ func (b *Block) DecoderSpec() hcldec.Spec { 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 { case NestingSingle, NestingGroup: ret[name] = &hcldec.BlockSpec{ @@ -134,13 +125,15 @@ func (b *Block) DecoderSpec() hcldec.Spec { ret[name] = &hcldec.BlockTupleSpec{ TypeName: name, Nested: childSpec, - MinItems: minItems, + MinItems: blockS.MinItems, + MaxItems: blockS.MaxItems, } } else { ret[name] = &hcldec.BlockListSpec{ TypeName: name, Nested: childSpec, - MinItems: minItems, + MinItems: blockS.MinItems, + MaxItems: blockS.MaxItems, } } case NestingSet: @@ -154,7 +147,8 @@ func (b *Block) DecoderSpec() hcldec.Spec { ret[name] = &hcldec.BlockSetSpec{ TypeName: name, Nested: childSpec, - MinItems: minItems, + MinItems: blockS.MinItems, + MaxItems: blockS.MaxItems, } case NestingMap: // We prefer to use a list where possible, since it makes our diff --git a/configs/configschema/decoder_spec_test.go b/configs/configschema/decoder_spec_test.go index 1eefc4d8b..a6571eaa6 100644 --- a/configs/configschema/decoder_spec_test.go +++ b/configs/configschema/decoder_spec_test.go @@ -344,15 +344,12 @@ func TestBlockDecoderSpec(t *testing.T) { }, &hcl.Block{ Type: "foo", - Body: hcl.EmptyBody(), + Body: unknownBody{hcl.EmptyBody()}, }, }, }), cty.ObjectVal(map[string]cty.Value{ - "foo": cty.ListVal([]cty.Value{ - cty.EmptyObjectVal, - cty.EmptyObjectVal, - }), + "foo": cty.UnknownVal(cty.List(cty.EmptyObject)), }), 0, // max items cannot be validated during decode }, @@ -372,14 +369,12 @@ func TestBlockDecoderSpec(t *testing.T) { Blocks: hcl.Blocks{ &hcl.Block{ Type: "foo", - Body: hcl.EmptyBody(), + Body: unknownBody{hcl.EmptyBody()}, }, }, }), cty.ObjectVal(map[string]cty.Value{ - "foo": cty.ListVal([]cty.Value{ - cty.EmptyObjectVal, - }), + "foo": cty.UnknownVal(cty.List(cty.EmptyObject)), }), 0, }, @@ -401,6 +396,7 @@ func TestBlockDecoderSpec(t *testing.T) { for name, test := range tests { t.Run(name, func(t *testing.T) { spec := test.Schema.DecoderSpec() + got, diags := hcldec.Decode(test.TestBody, spec, nil) if 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) { tests := map[string]struct { Schema *Attribute