github.com/hashicorp/packer@v1.14.3/hcl2template/function/templatefile_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package function 5 6 import ( 7 "fmt" 8 "path/filepath" 9 "testing" 10 11 "github.com/hashicorp/go-cty-funcs/filesystem" 12 "github.com/zclconf/go-cty/cty" 13 "github.com/zclconf/go-cty/cty/function" 14 "github.com/zclconf/go-cty/cty/function/stdlib" 15 ) 16 17 func TestTemplateFile(t *testing.T) { 18 tests := []struct { 19 Path cty.Value 20 Vars cty.Value 21 Want cty.Value 22 Err string 23 }{ 24 { 25 cty.StringVal("testdata/hello.txt"), 26 cty.EmptyObjectVal, 27 cty.StringVal("Hello World"), 28 ``, 29 }, 30 { 31 cty.StringVal("testdata/icon.png"), 32 cty.EmptyObjectVal, 33 cty.NilVal, 34 `contents of testdata/icon.png are not valid UTF-8; use the filebase64 function to obtain the Base64 encoded contents or the other file functions (e.g. filemd5, filesha256) to obtain file hashing results instead`, 35 }, 36 { 37 cty.StringVal("testdata/missing"), 38 cty.EmptyObjectVal, 39 cty.NilVal, 40 `no file exists at ` + filepath.Clean("testdata/missing"), 41 }, 42 { 43 cty.StringVal("testdata/hello.tmpl"), 44 cty.MapVal(map[string]cty.Value{ 45 "name": cty.StringVal("Jodie"), 46 }), 47 cty.StringVal("Hello, Jodie!"), 48 ``, 49 }, 50 { 51 cty.StringVal("testdata/hello.tmpl"), 52 cty.MapVal(map[string]cty.Value{ 53 "name!": cty.StringVal("Jodie"), 54 }), 55 cty.NilVal, 56 `invalid template variable name "name!": must start with a letter, followed by zero or more letters, digits, and underscores`, 57 }, 58 { 59 cty.StringVal("testdata/hello.tmpl"), 60 cty.ObjectVal(map[string]cty.Value{ 61 "name": cty.StringVal("Jimbo"), 62 }), 63 cty.StringVal("Hello, Jimbo!"), 64 ``, 65 }, 66 { 67 cty.StringVal("testdata/hello.tmpl"), 68 cty.EmptyObjectVal, 69 cty.NilVal, 70 `vars map does not contain key "name", referenced at testdata/hello.tmpl:1,10-14`, 71 }, 72 { 73 cty.StringVal("testdata/func.tmpl"), 74 cty.ObjectVal(map[string]cty.Value{ 75 "list": cty.ListVal([]cty.Value{ 76 cty.StringVal("a"), 77 cty.StringVal("b"), 78 cty.StringVal("c"), 79 }), 80 }), 81 cty.StringVal("The items are a, b, c"), 82 ``, 83 }, 84 { 85 cty.StringVal("testdata/recursive.tmpl"), 86 cty.MapValEmpty(cty.String), 87 cty.NilVal, 88 `testdata/recursive.tmpl:1,3-16: Error in function call; Call to function "templatefile" failed: cannot recursively call templatefile from inside templatefile call.`, 89 }, 90 { 91 cty.StringVal("testdata/list.tmpl"), 92 cty.ObjectVal(map[string]cty.Value{ 93 "list": cty.ListVal([]cty.Value{ 94 cty.StringVal("a"), 95 cty.StringVal("b"), 96 cty.StringVal("c"), 97 }), 98 }), 99 cty.StringVal("- a\n- b\n- c\n"), 100 ``, 101 }, 102 { 103 cty.StringVal("testdata/list.tmpl"), 104 cty.ObjectVal(map[string]cty.Value{ 105 "list": cty.True, 106 }), 107 cty.NilVal, 108 `testdata/list.tmpl:1,13-17: Iteration over non-iterable value; A value of type bool cannot be used as the collection in a 'for' expression.`, 109 }, 110 { 111 cty.StringVal("testdata/bare.tmpl"), 112 cty.ObjectVal(map[string]cty.Value{ 113 "val": cty.True, 114 }), 115 cty.True, // since this template contains only an interpolation, its true value shines through 116 ``, 117 }, 118 } 119 120 templateFileFn := MakeTemplateFileFunc(".", func() map[string]function.Function { 121 return map[string]function.Function{ 122 "join": stdlib.JoinFunc, 123 "templatefile": filesystem.MakeFileFunc(".", false), // just a placeholder, since templatefile itself overrides this 124 } 125 }) 126 127 for _, test := range tests { 128 t.Run(fmt.Sprintf("TemplateFile(%#v, %#v)", test.Path, test.Vars), func(t *testing.T) { 129 got, err := templateFileFn.Call([]cty.Value{test.Path, test.Vars}) 130 131 if argErr, ok := err.(function.ArgError); ok { 132 if argErr.Index < 0 || argErr.Index > 1 { 133 t.Errorf("ArgError index %d is out of range for templatefile (must be 0 or 1)", argErr.Index) 134 } 135 } 136 137 if test.Err != "" { 138 if err == nil { 139 t.Fatal("succeeded; want error") 140 } 141 if got, want := err.Error(), test.Err; got != want { 142 t.Errorf("wrong error\ngot: %s\nwant: %s", got, want) 143 } 144 return 145 } else if err != nil { 146 t.Fatalf("unexpected error: %s", err) 147 } 148 149 if !got.RawEquals(test.Want) { 150 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 151 } 152 }) 153 } 154 }