blob: 6e53a95750a2b36ac235aa221892a278b9fdb6c3 [file] [log] [blame]
package terraform
import (
"testing"
"github.com/hashicorp/terraform/internal/configs"
"github.com/zclconf/go-cty/cty"
)
func TestCheckInputVariables(t *testing.T) {
c := testModule(t, "input-variables")
t.Run("No variables set", func(t *testing.T) {
// No variables set
diags := checkInputVariables(c.Module.Variables, nil)
if !diags.HasErrors() {
t.Fatal("check succeeded, but want errors")
}
// Required variables set, optional variables unset
// This is still an error at this layer, since it's the caller's
// responsibility to have already merged in any default values.
diags = checkInputVariables(c.Module.Variables, InputValues{
"foo": &InputValue{
Value: cty.StringVal("bar"),
SourceType: ValueFromCLIArg,
},
})
if !diags.HasErrors() {
t.Fatal("check succeeded, but want errors")
}
})
t.Run("All variables set", func(t *testing.T) {
diags := checkInputVariables(c.Module.Variables, InputValues{
"foo": &InputValue{
Value: cty.StringVal("bar"),
SourceType: ValueFromCLIArg,
},
"bar": &InputValue{
Value: cty.StringVal("baz"),
SourceType: ValueFromCLIArg,
},
"map": &InputValue{
Value: cty.StringVal("baz"), // okay because config has no type constraint
SourceType: ValueFromCLIArg,
},
"object_map": &InputValue{
Value: cty.MapVal(map[string]cty.Value{
"uno": cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("baz"),
"bar": cty.NumberIntVal(2), // type = any
}),
"dos": cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("bat"),
"bar": cty.NumberIntVal(99), // type = any
}),
}),
SourceType: ValueFromCLIArg,
},
"object_list": &InputValue{
Value: cty.ListVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("baz"),
"bar": cty.NumberIntVal(2), // type = any
}),
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("bang"),
"bar": cty.NumberIntVal(42), // type = any
}),
}),
SourceType: ValueFromCLIArg,
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
})
t.Run("Invalid Complex Types", func(t *testing.T) {
diags := checkInputVariables(c.Module.Variables, InputValues{
"foo": &InputValue{
Value: cty.StringVal("bar"),
SourceType: ValueFromCLIArg,
},
"bar": &InputValue{
Value: cty.StringVal("baz"),
SourceType: ValueFromCLIArg,
},
"map": &InputValue{
Value: cty.StringVal("baz"), // okay because config has no type constraint
SourceType: ValueFromCLIArg,
},
"object_map": &InputValue{
Value: cty.MapVal(map[string]cty.Value{
"uno": cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("baz"),
"bar": cty.NumberIntVal(2), // type = any
}),
"dos": cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("bat"),
"bar": cty.NumberIntVal(99), // type = any
}),
}),
SourceType: ValueFromCLIArg,
},
"object_list": &InputValue{
Value: cty.TupleVal([]cty.Value{
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("baz"),
"bar": cty.NumberIntVal(2), // type = any
}),
cty.ObjectVal(map[string]cty.Value{
"foo": cty.StringVal("bang"),
"bar": cty.StringVal("42"), // type = any, but mismatch with the first list item
}),
}),
SourceType: ValueFromCLIArg,
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
})
}
// testInputValuesUnset is a helper for constructing InputValues values for
// situations where all of the root module variables are optional and a
// test case intends to just use those default values and not override them
// at all.
//
// In other words, this constructs an InputValues with one entry per given
// input variable declaration where all of them are declared as unset.
func testInputValuesUnset(decls map[string]*configs.Variable) InputValues {
if len(decls) == 0 {
return nil
}
ret := make(InputValues, len(decls))
for name := range decls {
ret[name] = &InputValue{
Value: cty.NilVal,
SourceType: ValueFromUnknown,
}
}
return ret
}