functions: Fix missing defaults for objects/tuples

If no default is specified for a nested optional structural typed
attribute, the defaults function should just pass through its input.
Before this commit the function assumed that the fallback value was
always of the correct type, which would panic.
This commit is contained in:
Alisdair McDiarmid 2021-03-12 18:14:14 -05:00
parent 0bbe583eb8
commit 7f97bd4489
2 changed files with 55 additions and 2 deletions

View File

@ -97,7 +97,11 @@ func defaultsApply(input, fallback cty.Value) cty.Value {
// For structural types, a null input value must be passed through. We
// do not apply default values for missing optional structural values,
// only their contents.
if input.IsNull() {
//
// We also pass through the input if the fallback value is null. This
// can happen if the given defaults do not include a value for this
// attribute.
if input.IsNull() || fallback.IsNull() {
return input
}
atys := wantTy.AttributeTypes()
@ -116,7 +120,11 @@ func defaultsApply(input, fallback cty.Value) cty.Value {
// For structural types, a null input value must be passed through. We
// do not apply default values for missing optional structural values,
// only their contents.
if input.IsNull() {
//
// We also pass through the input if the fallback value is null. This
// can happen if the given defaults do not include a value for this
// attribute.
if input.IsNull() || fallback.IsNull() {
return input
}

View File

@ -398,6 +398,51 @@ func TestDefaults(t *testing.T) {
"b": cty.NullVal(cty.Tuple([]cty.Type{cty.String, cty.String})),
}),
},
// When applying default values to structural types, we permit null
// values in the defaults, and just pass through the input value.
{
Input: cty.ObjectVal(map[string]cty.Value{
"a": cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"p": cty.StringVal("xyz"),
"q": cty.StringVal("xyz"),
}),
}),
"b": cty.SetVal([]cty.Value{
cty.TupleVal([]cty.Value{
cty.NumberIntVal(0),
cty.NumberIntVal(2),
}),
cty.TupleVal([]cty.Value{
cty.NumberIntVal(1),
cty.NumberIntVal(3),
}),
}),
"c": cty.NullVal(cty.String),
}),
Defaults: cty.ObjectVal(map[string]cty.Value{
"c": cty.StringVal("tada"),
}),
Want: cty.ObjectVal(map[string]cty.Value{
"a": cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"p": cty.StringVal("xyz"),
"q": cty.StringVal("xyz"),
}),
}),
"b": cty.SetVal([]cty.Value{
cty.TupleVal([]cty.Value{
cty.NumberIntVal(0),
cty.NumberIntVal(2),
}),
cty.TupleVal([]cty.Value{
cty.NumberIntVal(1),
cty.NumberIntVal(3),
}),
}),
"c": cty.StringVal("tada"),
}),
},
// When applying default values to collection types, null collections in the
// input should result in empty collections in the output.
{