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  }