package integrationtest import ( "testing" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/ext/typeexpr" "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" ) // TestTypeConvertFunc is an integration test of all of the layers involved // in making the type conversion function from ext/typeexpr work. // // This requires co-operation between the hclsyntax package, the ext/typeexpr // package, and the underlying cty functionality in order to work correctly. // // There are unit tests for the function implementation itself in the // ext/typeexpr package, so this test is focused on making sure the function // is given the opportunity to decode the second argument as a type expression // when the function is called from HCL native syntax. func TestTypeConvertFunc(t *testing.T) { // The convert function is special because it takes a type expression // rather than a value expression as its second argument. In this case, // we're asking it to convert a tuple into a list of strings: const exprSrc = `convert(["hello"], list(string))` // It achieves this by marking that second argument as being of a custom // type (a "capsule type", in cty terminology) that has a special // annotation which hclsyntax.FunctionCallExpr understands as allowing // the type to handle the analysis of the unevaluated expression, instead // of evaluating it as normal. // // To see more details of how this works, look at the definitions of // typexpr.TypeConstraintType and typeexpr.ConvertFunc, and at the // implementation of hclsyntax.FunctionCallExpr.Value. expr, diags := hclsyntax.ParseExpression([]byte(exprSrc), "", hcl.Pos{Line: 1, Column: 1}) if diags.HasErrors() { t.Fatalf("unexpected problems: %s", diags.Error()) } ctx := &hcl.EvalContext{ Functions: map[string]function.Function{ "convert": typeexpr.ConvertFunc, }, } got, diags := expr.Value(ctx) if diags.HasErrors() { t.Fatalf("unexpected problems: %s", diags.Error()) } want := cty.ListVal([]cty.Value{cty.StringVal("hello")}) if !want.RawEquals(got) { t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want) } }