lang/funcs: `matchkeys` - unify type for keys and searchset

Added higher-level test for matchkeys to exercise mixing
types in searchset. This had to be in the functions tests so the HCL
auto conversion from tuple to list would occur.
This commit is contained in:
Kristin Laemmert 2019-06-04 08:36:30 -04:00
parent f2a14d7c18
commit 30a924e162
3 changed files with 53 additions and 4 deletions

View File

@ -800,6 +800,8 @@ var MatchkeysFunc = function.New(&function.Spec{
},
},
Type: func(args []cty.Value) (cty.Type, error) {
// Verify that args[1] (keys) and args[2] (searchset) are of the same
// (or unifiable) type
argTypes := make([]cty.Type, 2)
for i := 0; i < 2; i++ {
argTypes[i] = args[i+1].Type()
@ -807,9 +809,10 @@ var MatchkeysFunc = function.New(&function.Spec{
ty, _ := convert.UnifyUnsafe(argTypes)
if ty == cty.NilType {
return cty.NilType, errors.New("lists must be of the same type")
return cty.NilType, errors.New("keys and searchset must be of the same type")
}
// the return type is based on args[0] (values)
return args[0].Type(), nil
},
Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
@ -822,10 +825,18 @@ var MatchkeysFunc = function.New(&function.Spec{
}
output := make([]cty.Value, 0)
values := args[0]
keys := args[1]
searchset := args[2]
// Keys and searchset must be the same type.
// We can skip error checking here because we've already verified that
// they can be unified in the Type function
argTypes := make([]cty.Type, 2)
for i := 0; i < 2; i++ {
argTypes[i] = args[i+1].Type()
}
ty, _ := convert.UnifyUnsafe(argTypes)
keys, _ := convert.Convert(args[1], ty)
searchset, _ := convert.Convert(args[2], ty)
// if searchset is empty, return an empty list.
if searchset.LengthInt() == 0 {

View File

@ -1896,6 +1896,37 @@ func TestMatchkeys(t *testing.T) {
cty.ListValEmpty(cty.String),
false,
},
{ // complex values: values is a different type from keys and searchset
cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
}),
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("baz"),
}),
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("beep"),
}),
}),
cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("b"),
cty.StringVal("c"),
}),
cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("c"),
}),
cty.ListVal([]cty.Value{
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("bar"),
}),
cty.MapVal(map[string]cty.Value{
"foo": cty.StringVal("beep"),
}),
}),
false,
},
// errors
{ // different types
cty.ListVal([]cty.Value{

View File

@ -459,6 +459,13 @@ func TestFunctions(t *testing.T) {
cty.StringVal("a"),
}),
},
{ // mixing types in searchset
`matchkeys(["a", "b", "c"], [1, 2, 3], [1, "3"])`,
cty.ListVal([]cty.Value{
cty.StringVal("a"),
cty.StringVal("c"),
}),
},
},
"max": {