package zclsyntax import ( "testing" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/function" "github.com/zclconf/go-cty/cty/function/stdlib" "github.com/zclconf/go-zcl/zcl" ) func TestFunctionCallExprValue(t *testing.T) { funcs := map[string]function.Function{ "length": stdlib.StrlenFunc, "jsondecode": stdlib.JSONDecodeFunc, } tests := map[string]struct { expr *FunctionCallExpr ctx *zcl.EvalContext want cty.Value diagCount int }{ "valid call with no conversions": { &FunctionCallExpr{ Name: "length", Args: []Expression{ &LiteralValueExpr{ Val: cty.StringVal("hello"), }, }, }, &zcl.EvalContext{ Functions: funcs, }, cty.NumberIntVal(5), 0, }, "valid call with arg conversion": { &FunctionCallExpr{ Name: "length", Args: []Expression{ &LiteralValueExpr{ Val: cty.BoolVal(true), }, }, }, &zcl.EvalContext{ Functions: funcs, }, cty.NumberIntVal(4), // length of string "true" 0, }, "valid call with unknown arg": { &FunctionCallExpr{ Name: "length", Args: []Expression{ &LiteralValueExpr{ Val: cty.UnknownVal(cty.String), }, }, }, &zcl.EvalContext{ Functions: funcs, }, cty.UnknownVal(cty.Number), 0, }, "valid call with unknown arg needing conversion": { &FunctionCallExpr{ Name: "length", Args: []Expression{ &LiteralValueExpr{ Val: cty.UnknownVal(cty.Bool), }, }, }, &zcl.EvalContext{ Functions: funcs, }, cty.UnknownVal(cty.Number), 0, }, "valid call with dynamic arg": { &FunctionCallExpr{ Name: "length", Args: []Expression{ &LiteralValueExpr{ Val: cty.DynamicVal, }, }, }, &zcl.EvalContext{ Functions: funcs, }, cty.UnknownVal(cty.Number), 0, }, "invalid arg type": { &FunctionCallExpr{ Name: "length", Args: []Expression{ &LiteralValueExpr{ Val: cty.ListVal([]cty.Value{cty.StringVal("hello")}), }, }, }, &zcl.EvalContext{ Functions: funcs, }, cty.DynamicVal, 1, }, "function with dynamic return type": { &FunctionCallExpr{ Name: "jsondecode", Args: []Expression{ &LiteralValueExpr{ Val: cty.StringVal(`"hello"`), }, }, }, &zcl.EvalContext{ Functions: funcs, }, cty.StringVal("hello"), 0, }, "function with dynamic return type unknown arg": { &FunctionCallExpr{ Name: "jsondecode", Args: []Expression{ &LiteralValueExpr{ Val: cty.UnknownVal(cty.String), }, }, }, &zcl.EvalContext{ Functions: funcs, }, cty.DynamicVal, // type depends on arg value 0, }, "error in function": { &FunctionCallExpr{ Name: "jsondecode", Args: []Expression{ &LiteralValueExpr{ Val: cty.StringVal("invalid-json"), }, }, }, &zcl.EvalContext{ Functions: funcs, }, cty.DynamicVal, 1, // JSON parse error }, "unknown function": { &FunctionCallExpr{ Name: "lenth", Args: []Expression{}, }, &zcl.EvalContext{ Functions: funcs, }, cty.DynamicVal, 1, }, } for name, test := range tests { t.Run(name, func(t *testing.T) { got, diags := test.expr.Value(test.ctx) 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.Error()) } } if !got.RawEquals(test.want) { t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.want) } }) } }