Skip to content

Commit

Permalink
Merge pull request hashicorp#27979 from hashicorp/alisdair/defaults-f…
Browse files Browse the repository at this point in the history
…ixes

functions: Fix panics in defaults
  • Loading branch information
alisdair authored Mar 5, 2021
2 parents ac8c6c1 + 66f8d1c commit 98899df
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 8 deletions.
20 changes: 12 additions & 8 deletions lang/funcs/defaults.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,11 @@ func defaultsApply(input, fallback cty.Value) cty.Value {
case wantTy.IsMapType():
newVals := map[string]cty.Value{}

for it := input.ElementIterator(); it.Next(); {
k, v := it.Element()
newVals[k.AsString()] = defaultsApply(v, fallback)
if !input.IsNull() {
for it := input.ElementIterator(); it.Next(); {
k, v := it.Element()
newVals[k.AsString()] = defaultsApply(v, fallback)
}
}

if len(newVals) == 0 {
Expand All @@ -139,10 +141,12 @@ func defaultsApply(input, fallback cty.Value) cty.Value {
case wantTy.IsListType(), wantTy.IsSetType():
var newVals []cty.Value

for it := input.ElementIterator(); it.Next(); {
_, v := it.Element()
newV := defaultsApply(v, fallback)
newVals = append(newVals, newV)
if !input.IsNull() {
for it := input.ElementIterator(); it.Next(); {
_, v := it.Element()
newV := defaultsApply(v, fallback)
newVals = append(newVals, newV)
}
}

if len(newVals) == 0 {
Expand Down Expand Up @@ -183,7 +187,7 @@ func defaultsAssertSuitableFallback(wantTy, fallbackTy cty.Type, fallbackPath ct
if fallbackTy.Equals(wantTy) {
return nil
}
conversion := convert.GetConversionUnsafe(fallbackTy, wantTy)
conversion := convert.GetConversion(fallbackTy, wantTy)
if conversion == nil {
msg := convert.MismatchMessage(fallbackTy, wantTy)
return fallbackPath.NewErrorf("invalid default value for %s: %s", wantTy.FriendlyName(), msg)
Expand Down
51 changes: 51 additions & 0 deletions lang/funcs/defaults_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,57 @@ func TestDefaults(t *testing.T) {
Defaults: cty.StringVal("hello"),
WantErr: `only object types and collections of object types can have defaults applied`,
},
// When applying default values to collection types, null collections in the
// input should result in empty collections in the output.
{
Input: cty.ObjectVal(map[string]cty.Value{
"a": cty.NullVal(cty.List(cty.String)),
"b": cty.NullVal(cty.Map(cty.String)),
"c": cty.NullVal(cty.Set(cty.String)),
}),
Defaults: cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("hello"),
"b": cty.StringVal("hi"),
"c": cty.StringVal("greetings"),
}),
Want: cty.ObjectVal(map[string]cty.Value{
"a": cty.ListValEmpty(cty.String),
"b": cty.MapValEmpty(cty.String),
"c": cty.SetValEmpty(cty.String),
}),
},
// When specifying fallbacks, we allow mismatched primitive attribute
// types so long as a safe conversion is possible. This means that we
// can accept number or boolean values for string attributes.
{
Input: cty.ObjectVal(map[string]cty.Value{
"a": cty.NullVal(cty.String),
"b": cty.NullVal(cty.String),
"c": cty.NullVal(cty.String),
}),
Defaults: cty.ObjectVal(map[string]cty.Value{
"a": cty.NumberIntVal(5),
"b": cty.True,
"c": cty.StringVal("greetings"),
}),
Want: cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("5"),
"b": cty.StringVal("true"),
"c": cty.StringVal("greetings"),
}),
},
// Fallbacks with mismatched primitive attribute types which do not
// have safe conversions must not pass the suitable fallback check,
// even if unsafe conversion would be possible.
{
Input: cty.ObjectVal(map[string]cty.Value{
"a": cty.NullVal(cty.Bool),
}),
Defaults: cty.ObjectVal(map[string]cty.Value{
"a": cty.StringVal("5"),
}),
WantErr: ".a: invalid default value for bool: bool required",
},
}

for _, test := range tests {
Expand Down

0 comments on commit 98899df

Please sign in to comment.