github.com/hashicorp/hcl/v2@v2.20.0/ext/userfunc/decode_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package userfunc
     5  
     6  import (
     7  	"fmt"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/hcl/v2"
    11  	"github.com/hashicorp/hcl/v2/hclsyntax"
    12  	"github.com/zclconf/go-cty/cty"
    13  )
    14  
    15  func TestDecodeUserFunctions(t *testing.T) {
    16  	tests := []struct {
    17  		src       string
    18  		testExpr  string
    19  		baseCtx   *hcl.EvalContext
    20  		want      cty.Value
    21  		diagCount int
    22  	}{
    23  		{
    24  			`
    25  function "greet" {
    26    params = [name]
    27    result = "Hello, ${name}."
    28  }
    29  `,
    30  			`greet("Ermintrude")`,
    31  			nil,
    32  			cty.StringVal("Hello, Ermintrude."),
    33  			0,
    34  		},
    35  		{
    36  			`
    37  function "greet" {
    38    params = [name]
    39    result = "Hello, ${name}."
    40  }
    41  `,
    42  			`greet()`,
    43  			nil,
    44  			cty.DynamicVal,
    45  			1, // missing value for "name"
    46  		},
    47  		{
    48  			`
    49  function "greet" {
    50    params = [name]
    51    result = "Hello, ${name}."
    52  }
    53  `,
    54  			`greet("Ermintrude", "extra")`,
    55  			nil,
    56  			cty.DynamicVal,
    57  			1, // too many arguments
    58  		},
    59  		{
    60  			`
    61  function "add" {
    62    params = [a, b]
    63    result = a + b
    64  }
    65  `,
    66  			`add(1, 5)`,
    67  			nil,
    68  			cty.NumberIntVal(6),
    69  			0,
    70  		},
    71  		{
    72  			`
    73  function "argstuple" {
    74    params = []
    75    variadic_param = args
    76    result = args
    77  }
    78  `,
    79  			`argstuple("a", true, 1)`,
    80  			nil,
    81  			cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.True, cty.NumberIntVal(1)}),
    82  			0,
    83  		},
    84  		{
    85  			`
    86  function "missing_var" {
    87    params = []
    88    result = nonexist
    89  }
    90  `,
    91  			`missing_var()`,
    92  			nil,
    93  			cty.DynamicVal,
    94  			1, // no variable named "nonexist"
    95  		},
    96  		{
    97  			`
    98  function "closure" {
    99    params = []
   100    result = upvalue
   101  }
   102  `,
   103  			`closure()`,
   104  			&hcl.EvalContext{
   105  				Variables: map[string]cty.Value{
   106  					"upvalue": cty.True,
   107  				},
   108  			},
   109  			cty.True,
   110  			0,
   111  		},
   112  		{
   113  			`
   114  function "neg" {
   115    params = [val]
   116    result = -val
   117  }
   118  function "add" {
   119    params = [a, b]
   120    result = a + b
   121  }
   122  `,
   123  			`neg(add(1, 3))`,
   124  			nil,
   125  			cty.NumberIntVal(-4),
   126  			0,
   127  		},
   128  		{
   129  			`
   130  function "neg" {
   131    parrams = [val]
   132    result = -val
   133  }
   134  `,
   135  			`null`,
   136  			nil,
   137  			cty.NullVal(cty.DynamicPseudoType),
   138  			2, // missing attribute "params", and unknown attribute "parrams"
   139  		},
   140  	}
   141  
   142  	for i, test := range tests {
   143  		t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
   144  			f, diags := hclsyntax.ParseConfig([]byte(test.src), "config", hcl.Pos{Line: 1, Column: 1})
   145  			if f == nil || f.Body == nil {
   146  				t.Fatalf("got nil file or body")
   147  			}
   148  
   149  			funcs, _, funcsDiags := decodeUserFunctions(f.Body, "function", func() *hcl.EvalContext {
   150  				return test.baseCtx
   151  			})
   152  			diags = append(diags, funcsDiags...)
   153  
   154  			expr, exprParseDiags := hclsyntax.ParseExpression([]byte(test.testExpr), "testexpr", hcl.Pos{Line: 1, Column: 1})
   155  			diags = append(diags, exprParseDiags...)
   156  			if expr == nil {
   157  				t.Fatalf("parsing test expr returned nil")
   158  			}
   159  
   160  			got, exprDiags := expr.Value(&hcl.EvalContext{
   161  				Functions: funcs,
   162  			})
   163  			diags = append(diags, exprDiags...)
   164  
   165  			if len(diags) != test.diagCount {
   166  				t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.diagCount)
   167  				for _, diag := range diags {
   168  					t.Logf("- %s", diag)
   169  				}
   170  			}
   171  
   172  			if !got.RawEquals(test.want) {
   173  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.want)
   174  			}
   175  		})
   176  	}
   177  }