mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-01 11:47:07 -06:00
2f8f7d6f4d
It's not normally necessary to make explicit type conversions in Terraform because the language implicitly converts as necessary, but explicit conversions are useful in a few specialized cases: - When defining output values for a reusable module, it may be desirable to force a "cleaner" output type than would naturally arise from a computation, such as forcing a string containing digits into a number. - Our 0.12upgrade mechanism will use some of these to replace use of the undocumented, hidden type conversion functions in HIL, and force particular type interpretations in some tricky cases. - We've found that type conversion functions can be useful as _temporary_ workarounds for bugs in Terraform and in providers where implicit type conversion isn't working correctly or a type constraint isn't specified precisely enough for the automatic conversion behavior. These all follow the same convention of being named "to" followed by a short type name. Since we've had a long-standing convention of running all the words together in lowercase in function names, we stick to that here even though some of these names are quite strange, because these should be rarely-used functions anyway.
132 lines
2.7 KiB
Go
132 lines
2.7 KiB
Go
package funcs
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
func TestTo(t *testing.T) {
|
|
tests := []struct {
|
|
Value cty.Value
|
|
TargetTy cty.Type
|
|
Want cty.Value
|
|
Err string
|
|
}{
|
|
{
|
|
cty.StringVal("a"),
|
|
cty.String,
|
|
cty.StringVal("a"),
|
|
``,
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.String),
|
|
cty.String,
|
|
cty.UnknownVal(cty.String),
|
|
``,
|
|
},
|
|
{
|
|
cty.NullVal(cty.String),
|
|
cty.String,
|
|
cty.NullVal(cty.String),
|
|
``,
|
|
},
|
|
{
|
|
cty.True,
|
|
cty.String,
|
|
cty.StringVal("true"),
|
|
``,
|
|
},
|
|
{
|
|
cty.StringVal("a"),
|
|
cty.Bool,
|
|
cty.DynamicVal,
|
|
`cannot convert "a" to bool; only the strings "true" or "false" are allowed`,
|
|
},
|
|
{
|
|
cty.StringVal("a"),
|
|
cty.Number,
|
|
cty.DynamicVal,
|
|
`cannot convert "a" to number; given string must be a decimal representation of a number`,
|
|
},
|
|
{
|
|
cty.NullVal(cty.String),
|
|
cty.Number,
|
|
cty.NullVal(cty.Number),
|
|
``,
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.Bool),
|
|
cty.String,
|
|
cty.UnknownVal(cty.String),
|
|
``,
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.String),
|
|
cty.Bool,
|
|
cty.UnknownVal(cty.Bool), // conversion is optimistic
|
|
``,
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.True}),
|
|
cty.List(cty.String),
|
|
cty.ListVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("true")}),
|
|
``,
|
|
},
|
|
{
|
|
cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.True}),
|
|
cty.Set(cty.String),
|
|
cty.SetVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("true")}),
|
|
``,
|
|
},
|
|
{
|
|
cty.ObjectVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.True}),
|
|
cty.Map(cty.String),
|
|
cty.MapVal(map[string]cty.Value{"foo": cty.StringVal("hello"), "bar": cty.StringVal("true")}),
|
|
``,
|
|
},
|
|
{
|
|
cty.EmptyTupleVal,
|
|
cty.String,
|
|
cty.DynamicVal,
|
|
`cannot convert tuple to string`,
|
|
},
|
|
{
|
|
cty.UnknownVal(cty.EmptyTuple),
|
|
cty.String,
|
|
cty.DynamicVal,
|
|
`cannot convert tuple to string`,
|
|
},
|
|
{
|
|
cty.EmptyObjectVal,
|
|
cty.Object(map[string]cty.Type{"foo": cty.String}),
|
|
cty.DynamicVal,
|
|
`incompatible object type for conversion: attribute "foo" is required`,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(fmt.Sprintf("to %s(%#v)", test.TargetTy.FriendlyNameForConstraint(), test.Value), func(t *testing.T) {
|
|
f := MakeToFunc(test.TargetTy)
|
|
got, err := f.Call([]cty.Value{test.Value})
|
|
|
|
if test.Err != "" {
|
|
if err == nil {
|
|
t.Fatal("succeeded; want error")
|
|
}
|
|
if got, want := err.Error(), test.Err; got != want {
|
|
t.Fatalf("wrong error\ngot: %s\nwant: %s", got, want)
|
|
}
|
|
return
|
|
} else if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
if !got.RawEquals(test.Want) {
|
|
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
|
|
}
|
|
})
|
|
}
|
|
}
|