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  }