6c4344623b
The main HCL package is more visible this way, and so it's easier than having to pick it out from dozens of other package directories.
175 lines
2.9 KiB
Go
175 lines
2.9 KiB
Go
package userfunc
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/hcl/v2/hclsyntax"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
func TestDecodeUserFunctions(t *testing.T) {
|
|
tests := []struct {
|
|
src string
|
|
testExpr string
|
|
baseCtx *hcl.EvalContext
|
|
want cty.Value
|
|
diagCount int
|
|
}{
|
|
{
|
|
`
|
|
function "greet" {
|
|
params = [name]
|
|
result = "Hello, ${name}."
|
|
}
|
|
`,
|
|
`greet("Ermintrude")`,
|
|
nil,
|
|
cty.StringVal("Hello, Ermintrude."),
|
|
0,
|
|
},
|
|
{
|
|
`
|
|
function "greet" {
|
|
params = [name]
|
|
result = "Hello, ${name}."
|
|
}
|
|
`,
|
|
`greet()`,
|
|
nil,
|
|
cty.DynamicVal,
|
|
1, // missing value for "name"
|
|
},
|
|
{
|
|
`
|
|
function "greet" {
|
|
params = [name]
|
|
result = "Hello, ${name}."
|
|
}
|
|
`,
|
|
`greet("Ermintrude", "extra")`,
|
|
nil,
|
|
cty.DynamicVal,
|
|
1, // too many arguments
|
|
},
|
|
{
|
|
`
|
|
function "add" {
|
|
params = [a, b]
|
|
result = a + b
|
|
}
|
|
`,
|
|
`add(1, 5)`,
|
|
nil,
|
|
cty.NumberIntVal(6),
|
|
0,
|
|
},
|
|
{
|
|
`
|
|
function "argstuple" {
|
|
params = []
|
|
variadic_param = args
|
|
result = args
|
|
}
|
|
`,
|
|
`argstuple("a", true, 1)`,
|
|
nil,
|
|
cty.TupleVal([]cty.Value{cty.StringVal("a"), cty.True, cty.NumberIntVal(1)}),
|
|
0,
|
|
},
|
|
{
|
|
`
|
|
function "missing_var" {
|
|
params = []
|
|
result = nonexist
|
|
}
|
|
`,
|
|
`missing_var()`,
|
|
nil,
|
|
cty.DynamicVal,
|
|
1, // no variable named "nonexist"
|
|
},
|
|
{
|
|
`
|
|
function "closure" {
|
|
params = []
|
|
result = upvalue
|
|
}
|
|
`,
|
|
`closure()`,
|
|
&hcl.EvalContext{
|
|
Variables: map[string]cty.Value{
|
|
"upvalue": cty.True,
|
|
},
|
|
},
|
|
cty.True,
|
|
0,
|
|
},
|
|
{
|
|
`
|
|
function "neg" {
|
|
params = [val]
|
|
result = -val
|
|
}
|
|
function "add" {
|
|
params = [a, b]
|
|
result = a + b
|
|
}
|
|
`,
|
|
`neg(add(1, 3))`,
|
|
nil,
|
|
cty.NumberIntVal(-4),
|
|
0,
|
|
},
|
|
{
|
|
`
|
|
function "neg" {
|
|
parrams = [val]
|
|
result = -val
|
|
}
|
|
`,
|
|
`null`,
|
|
nil,
|
|
cty.NullVal(cty.DynamicPseudoType),
|
|
2, // missing attribute "params", and unknown attribute "parrams"
|
|
},
|
|
}
|
|
|
|
for i, test := range tests {
|
|
t.Run(fmt.Sprintf("%02d", i), func(t *testing.T) {
|
|
f, diags := hclsyntax.ParseConfig([]byte(test.src), "config", hcl.Pos{Line: 1, Column: 1})
|
|
if f == nil || f.Body == nil {
|
|
t.Fatalf("got nil file or body")
|
|
}
|
|
|
|
funcs, _, funcsDiags := decodeUserFunctions(f.Body, "function", func() *hcl.EvalContext {
|
|
return test.baseCtx
|
|
})
|
|
diags = append(diags, funcsDiags...)
|
|
|
|
expr, exprParseDiags := hclsyntax.ParseExpression([]byte(test.testExpr), "testexpr", hcl.Pos{Line: 1, Column: 1})
|
|
diags = append(diags, exprParseDiags...)
|
|
if expr == nil {
|
|
t.Fatalf("parsing test expr returned nil")
|
|
}
|
|
|
|
got, exprDiags := expr.Value(&hcl.EvalContext{
|
|
Functions: funcs,
|
|
})
|
|
diags = append(diags, exprDiags...)
|
|
|
|
if len(diags) != test.diagCount {
|
|
t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.diagCount)
|
|
for _, diag := range diags {
|
|
t.Logf("- %s", diag)
|
|
}
|
|
}
|
|
|
|
if !got.RawEquals(test.want) {
|
|
t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.want)
|
|
}
|
|
})
|
|
}
|
|
}
|