add zero values to sets with a flatmap count of 1

If a flatmap value has a count of 1 and no other attributes, it usually
indicates the equivalent configuration of an empty (or default value)
set block. Treat this as containing a single zero value object and
insert that into the set.
This commit is contained in:
James Bardin 2019-01-08 11:51:21 -05:00
parent 3677522a28
commit f3c80b4765
2 changed files with 71 additions and 7 deletions

View File

@ -347,10 +347,8 @@ func hcl2ValueFromFlatmapSet(m map[string]string, prefix string, ty cty.Type) (c
return cty.UnknownVal(ty), nil return cty.UnknownVal(ty), nil
} }
// We actually don't really care about the "count" of a set for our strCount, exists := m[prefix+"#"]
// purposes here, but we do need to check if it _exists_ in order to if !exists {
// recognize the difference between null (not set at all) and empty.
if strCount, exists := m[prefix+"#"]; !exists {
return cty.NullVal(ty), nil return cty.NullVal(ty), nil
} else if strCount == UnknownVariableValue { } else if strCount == UnknownVariableValue {
return cty.UnknownVal(ty), nil return cty.UnknownVal(ty), nil
@ -394,7 +392,31 @@ func hcl2ValueFromFlatmapSet(m map[string]string, prefix string, ty cty.Type) (c
vals = append(vals, val) vals = append(vals, val)
} }
if len(vals) == 0 { if len(vals) == 0 && strCount == "1" {
// An empty set wouldn't be represented in the flatmap, so this must be
// a single empty object since the count is actually 1.
// Add an appropriately typed null value to the set.
var val cty.Value
switch {
case ety.IsMapType():
val = cty.MapValEmpty(ety)
case ety.IsListType():
val = cty.ListValEmpty(ety)
case ety.IsSetType():
val = cty.SetValEmpty(ety)
case ety.IsObjectType():
// TODO: cty.ObjectValEmpty
objectMap := map[string]cty.Value{}
for attr, ty := range ety.AttributeTypes() {
objectMap[attr] = cty.NullVal(ty)
}
val = cty.ObjectVal(objectMap)
default:
val = cty.NullVal(ety)
}
vals = append(vals, val)
} else if len(vals) == 0 {
return cty.SetValEmpty(ety), nil return cty.SetValEmpty(ety), nil
} }

View File

@ -679,10 +679,52 @@ func TestHCL2ValueFromFlatmap(t *testing.T) {
}), }),
}), }),
}, },
{
Flatmap: map[string]string{
"foo.#": "1",
},
Type: cty.Object(map[string]cty.Type{
"foo": cty.Set(cty.Object(map[string]cty.Type{
"bar": cty.String,
})),
}),
Want: cty.ObjectVal(map[string]cty.Value{
"foo": cty.SetVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"bar": cty.NullVal(cty.String),
}),
}),
}),
},
{
Flatmap: map[string]string{
"multi.#": "1",
"multi.2.set.#": "1",
"multi.2.set.3.required": "val",
},
Type: cty.Object(map[string]cty.Type{
"multi": cty.Set(cty.Object(map[string]cty.Type{
"set": cty.Set(cty.Object(map[string]cty.Type{
"required": cty.String,
})),
})),
}),
Want: cty.ObjectVal(map[string]cty.Value{
"multi": cty.SetVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"set": cty.SetVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"required": cty.StringVal("val"),
}),
}),
}),
}),
}),
},
} }
for _, test := range tests { for i, test := range tests {
t.Run(fmt.Sprintf("%#v as %#v", test.Flatmap, test.Type), func(t *testing.T) { t.Run(fmt.Sprintf("%d %#v as %#v", i, test.Flatmap, test.Type), func(t *testing.T) {
got, err := HCL2ValueFromFlatmap(test.Flatmap, test.Type) got, err := HCL2ValueFromFlatmap(test.Flatmap, test.Type)
if test.WantErr != "" { if test.WantErr != "" {