github.com/hashicorp/hcl/v2@v2.20.0/integrationtest/convertfunc_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package integrationtest 5 6 import ( 7 "testing" 8 9 "github.com/hashicorp/hcl/v2" 10 "github.com/hashicorp/hcl/v2/ext/typeexpr" 11 "github.com/hashicorp/hcl/v2/hclsyntax" 12 "github.com/zclconf/go-cty/cty" 13 "github.com/zclconf/go-cty/cty/function" 14 ) 15 16 // TestTypeConvertFunc is an integration test of all of the layers involved 17 // in making the type conversion function from ext/typeexpr work. 18 // 19 // This requires co-operation between the hclsyntax package, the ext/typeexpr 20 // package, and the underlying cty functionality in order to work correctly. 21 // 22 // There are unit tests for the function implementation itself in the 23 // ext/typeexpr package, so this test is focused on making sure the function 24 // is given the opportunity to decode the second argument as a type expression 25 // when the function is called from HCL native syntax. 26 func TestTypeConvertFunc(t *testing.T) { 27 // The convert function is special because it takes a type expression 28 // rather than a value expression as its second argument. In this case, 29 // we're asking it to convert a tuple into a list of strings: 30 const exprSrc = `convert(["hello"], list(string))` 31 // It achieves this by marking that second argument as being of a custom 32 // type (a "capsule type", in cty terminology) that has a special 33 // annotation which hclsyntax.FunctionCallExpr understands as allowing 34 // the type to handle the analysis of the unevaluated expression, instead 35 // of evaluating it as normal. 36 // 37 // To see more details of how this works, look at the definitions of 38 // typexpr.TypeConstraintType and typeexpr.ConvertFunc, and at the 39 // implementation of hclsyntax.FunctionCallExpr.Value. 40 41 expr, diags := hclsyntax.ParseExpression([]byte(exprSrc), "", hcl.Pos{Line: 1, Column: 1}) 42 if diags.HasErrors() { 43 t.Fatalf("unexpected problems: %s", diags.Error()) 44 } 45 46 ctx := &hcl.EvalContext{ 47 Functions: map[string]function.Function{ 48 "convert": typeexpr.ConvertFunc, 49 }, 50 } 51 got, diags := expr.Value(ctx) 52 if diags.HasErrors() { 53 t.Fatalf("unexpected problems: %s", diags.Error()) 54 } 55 want := cty.ListVal([]cty.Value{cty.StringVal("hello")}) 56 if !want.RawEquals(got) { 57 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, want) 58 } 59 }