github.com/opentofu/opentofu@v1.7.1/internal/lang/funcs/render_template_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package funcs 7 8 import ( 9 "testing" 10 11 "github.com/hashicorp/hcl/v2" 12 "github.com/opentofu/opentofu/internal/lang/marks" 13 "github.com/zclconf/go-cty/cty" 14 "github.com/zclconf/go-cty/cty/function" 15 ) 16 17 func TestRenderTemplate(t *testing.T) { 18 tests := map[string]struct { 19 Expr hcl.Expression 20 Vars cty.Value 21 Want cty.Value 22 Err string 23 }{ 24 "String interpolation with variable": { 25 hcl.StaticExpr(cty.StringVal("Hello, ${name}!"), hcl.Range{}), 26 cty.MapVal(map[string]cty.Value{ 27 "name": cty.StringVal("Jodie"), 28 }), 29 cty.StringVal("Hello, ${name}!"), 30 ``, 31 }, 32 "Looping through list": { 33 hcl.StaticExpr(cty.StringVal("Items: %{ for x in list ~} ${x} %{ endfor ~}"), hcl.Range{}), 34 cty.ObjectVal(map[string]cty.Value{ 35 "list": cty.ListVal([]cty.Value{ 36 cty.StringVal("a"), 37 cty.StringVal("b"), 38 cty.StringVal("c"), 39 }), 40 }), 41 cty.StringVal("Items: %{ for x in list ~} ${x} %{ endfor ~}"), 42 ``, 43 }, 44 "Looping through map": { 45 hcl.StaticExpr(cty.StringVal("%{ for key, value in list ~} ${key}:${value} %{ endfor ~}"), hcl.Range{}), 46 cty.ObjectVal(map[string]cty.Value{ 47 "list": cty.ObjectVal(map[string]cty.Value{ 48 "item1": cty.StringVal("a"), 49 "item2": cty.StringVal("b"), 50 "item3": cty.StringVal("c"), 51 }), 52 }), 53 cty.StringVal("%{ for key, value in list ~} ${key}:${value} %{ endfor ~}"), 54 ``, 55 }, 56 "Invalid template variable name": { 57 hcl.StaticExpr(cty.StringVal("Hello, ${1}!"), hcl.Range{}), 58 cty.MapVal(map[string]cty.Value{ 59 "1": cty.StringVal("Jodie"), 60 }), 61 cty.NilVal, 62 `invalid template variable name "1": must start with a letter, followed by zero or more letters, digits, and underscores`, 63 }, 64 "Interpolation of a boolean value": { 65 hcl.StaticExpr(cty.StringVal("${val}"), hcl.Range{}), 66 cty.ObjectVal(map[string]cty.Value{ 67 "val": cty.True, 68 }), 69 cty.StringVal("${val}"), 70 ``, 71 }, 72 "Sensitive string template": { 73 hcl.StaticExpr(cty.StringVal("My password is 1234").Mark(marks.Sensitive), hcl.Range{}), 74 cty.EmptyObjectVal, 75 cty.StringVal("My password is 1234").Mark(marks.Sensitive), 76 ``, 77 }, 78 "Sensitive template variable": { 79 hcl.StaticExpr(cty.StringVal("My password is ${pass}"), hcl.Range{}), 80 cty.ObjectVal(map[string]cty.Value{ 81 "pass": cty.StringVal("secret").Mark(marks.Sensitive), 82 }), 83 cty.StringVal("My password is ${pass}"), 84 ``, 85 }, 86 } 87 88 for name, test := range tests { 89 t.Run(name, func(t *testing.T) { 90 91 got, err := renderTemplate(test.Expr, test.Vars, map[string]function.Function{}) 92 93 if err != nil { 94 if test.Err == "" { 95 t.Fatalf("unexpected error: %s", err) 96 } else { 97 if got, want := err.Error(), test.Err; got != want { 98 t.Errorf("wrong error\ngot: %s\nwant: %s", got, want) 99 } 100 } 101 } else if test.Err != "" { 102 t.Fatal("succeeded; want error") 103 } else { 104 if !got.RawEquals(test.Want) { 105 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 106 } 107 } 108 }) 109 } 110 }