github.com/hugorut/terraform@v1.1.3/src/lang/funcs/filesystem_test.go (about)

     1  package funcs
     2  
     3  import (
     4  	"fmt"
     5  	"path/filepath"
     6  	"testing"
     7  
     8  	homedir "github.com/mitchellh/go-homedir"
     9  	"github.com/zclconf/go-cty/cty"
    10  	"github.com/zclconf/go-cty/cty/function"
    11  	"github.com/zclconf/go-cty/cty/function/stdlib"
    12  )
    13  
    14  func TestFile(t *testing.T) {
    15  	tests := []struct {
    16  		Path cty.Value
    17  		Want cty.Value
    18  		Err  bool
    19  	}{
    20  		{
    21  			cty.StringVal("testdata/hello.txt"),
    22  			cty.StringVal("Hello World"),
    23  			false,
    24  		},
    25  		{
    26  			cty.StringVal("testdata/icon.png"),
    27  			cty.NilVal,
    28  			true, // Not valid UTF-8
    29  		},
    30  		{
    31  			cty.StringVal("testdata/missing"),
    32  			cty.NilVal,
    33  			true, // no file exists
    34  		},
    35  	}
    36  
    37  	for _, test := range tests {
    38  		t.Run(fmt.Sprintf("File(\".\", %#v)", test.Path), func(t *testing.T) {
    39  			got, err := File(".", test.Path)
    40  
    41  			if test.Err {
    42  				if err == nil {
    43  					t.Fatal("succeeded; want error")
    44  				}
    45  				return
    46  			} else if err != nil {
    47  				t.Fatalf("unexpected error: %s", err)
    48  			}
    49  
    50  			if !got.RawEquals(test.Want) {
    51  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
    52  			}
    53  		})
    54  	}
    55  }
    56  
    57  func TestTemplateFile(t *testing.T) {
    58  	tests := []struct {
    59  		Path cty.Value
    60  		Vars cty.Value
    61  		Want cty.Value
    62  		Err  string
    63  	}{
    64  		{
    65  			cty.StringVal("testdata/hello.txt"),
    66  			cty.EmptyObjectVal,
    67  			cty.StringVal("Hello World"),
    68  			``,
    69  		},
    70  		{
    71  			cty.StringVal("testdata/icon.png"),
    72  			cty.EmptyObjectVal,
    73  			cty.NilVal,
    74  			`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`,
    75  		},
    76  		{
    77  			cty.StringVal("testdata/missing"),
    78  			cty.EmptyObjectVal,
    79  			cty.NilVal,
    80  			`no file exists at testdata/missing; this function works only with files that are distributed as part of the configuration source code, so if this file will be created by a resource in this configuration you must instead obtain this result from an attribute of that resource`,
    81  		},
    82  		{
    83  			cty.StringVal("testdata/hello.tmpl"),
    84  			cty.MapVal(map[string]cty.Value{
    85  				"name": cty.StringVal("Jodie"),
    86  			}),
    87  			cty.StringVal("Hello, Jodie!"),
    88  			``,
    89  		},
    90  		{
    91  			cty.StringVal("testdata/hello.tmpl"),
    92  			cty.MapVal(map[string]cty.Value{
    93  				"name!": cty.StringVal("Jodie"),
    94  			}),
    95  			cty.NilVal,
    96  			`invalid template variable name "name!": must start with a letter, followed by zero or more letters, digits, and underscores`,
    97  		},
    98  		{
    99  			cty.StringVal("testdata/hello.tmpl"),
   100  			cty.ObjectVal(map[string]cty.Value{
   101  				"name": cty.StringVal("Jimbo"),
   102  			}),
   103  			cty.StringVal("Hello, Jimbo!"),
   104  			``,
   105  		},
   106  		{
   107  			cty.StringVal("testdata/hello.tmpl"),
   108  			cty.EmptyObjectVal,
   109  			cty.NilVal,
   110  			`vars map does not contain key "name", referenced at testdata/hello.tmpl:1,10-14`,
   111  		},
   112  		{
   113  			cty.StringVal("testdata/func.tmpl"),
   114  			cty.ObjectVal(map[string]cty.Value{
   115  				"list": cty.ListVal([]cty.Value{
   116  					cty.StringVal("a"),
   117  					cty.StringVal("b"),
   118  					cty.StringVal("c"),
   119  				}),
   120  			}),
   121  			cty.StringVal("The items are a, b, c"),
   122  			``,
   123  		},
   124  		{
   125  			cty.StringVal("testdata/recursive.tmpl"),
   126  			cty.MapValEmpty(cty.String),
   127  			cty.NilVal,
   128  			`testdata/recursive.tmpl:1,3-16: Error in function call; Call to function "templatefile" failed: cannot recursively call templatefile from inside templatefile call.`,
   129  		},
   130  		{
   131  			cty.StringVal("testdata/list.tmpl"),
   132  			cty.ObjectVal(map[string]cty.Value{
   133  				"list": cty.ListVal([]cty.Value{
   134  					cty.StringVal("a"),
   135  					cty.StringVal("b"),
   136  					cty.StringVal("c"),
   137  				}),
   138  			}),
   139  			cty.StringVal("- a\n- b\n- c\n"),
   140  			``,
   141  		},
   142  		{
   143  			cty.StringVal("testdata/list.tmpl"),
   144  			cty.ObjectVal(map[string]cty.Value{
   145  				"list": cty.True,
   146  			}),
   147  			cty.NilVal,
   148  			`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.`,
   149  		},
   150  		{
   151  			cty.StringVal("testdata/bare.tmpl"),
   152  			cty.ObjectVal(map[string]cty.Value{
   153  				"val": cty.True,
   154  			}),
   155  			cty.True, // since this template contains only an interpolation, its true value shines through
   156  			``,
   157  		},
   158  	}
   159  
   160  	templateFileFn := MakeTemplateFileFunc(".", func() map[string]function.Function {
   161  		return map[string]function.Function{
   162  			"join":         stdlib.JoinFunc,
   163  			"templatefile": MakeFileFunc(".", false), // just a placeholder, since templatefile itself overrides this
   164  		}
   165  	})
   166  
   167  	for _, test := range tests {
   168  		t.Run(fmt.Sprintf("TemplateFile(%#v, %#v)", test.Path, test.Vars), func(t *testing.T) {
   169  			got, err := templateFileFn.Call([]cty.Value{test.Path, test.Vars})
   170  
   171  			if argErr, ok := err.(function.ArgError); ok {
   172  				if argErr.Index < 0 || argErr.Index > 1 {
   173  					t.Errorf("ArgError index %d is out of range for templatefile (must be 0 or 1)", argErr.Index)
   174  				}
   175  			}
   176  
   177  			if test.Err != "" {
   178  				if err == nil {
   179  					t.Fatal("succeeded; want error")
   180  				}
   181  				if got, want := err.Error(), test.Err; got != want {
   182  					t.Errorf("wrong error\ngot:  %s\nwant: %s", got, want)
   183  				}
   184  				return
   185  			} else if err != nil {
   186  				t.Fatalf("unexpected error: %s", err)
   187  			}
   188  
   189  			if !got.RawEquals(test.Want) {
   190  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   191  			}
   192  		})
   193  	}
   194  }
   195  
   196  func TestFileExists(t *testing.T) {
   197  	tests := []struct {
   198  		Path cty.Value
   199  		Want cty.Value
   200  		Err  bool
   201  	}{
   202  		{
   203  			cty.StringVal("testdata/hello.txt"),
   204  			cty.BoolVal(true),
   205  			false,
   206  		},
   207  		{
   208  			cty.StringVal(""), // empty path
   209  			cty.BoolVal(false),
   210  			true,
   211  		},
   212  		{
   213  			cty.StringVal("testdata/missing"),
   214  			cty.BoolVal(false),
   215  			false, // no file exists
   216  		},
   217  	}
   218  
   219  	for _, test := range tests {
   220  		t.Run(fmt.Sprintf("FileExists(\".\", %#v)", test.Path), func(t *testing.T) {
   221  			got, err := FileExists(".", test.Path)
   222  
   223  			if test.Err {
   224  				if err == nil {
   225  					t.Fatal("succeeded; want error")
   226  				}
   227  				return
   228  			} else if err != nil {
   229  				t.Fatalf("unexpected error: %s", err)
   230  			}
   231  
   232  			if !got.RawEquals(test.Want) {
   233  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   234  			}
   235  		})
   236  	}
   237  }
   238  
   239  func TestFileSet(t *testing.T) {
   240  	tests := []struct {
   241  		Path    cty.Value
   242  		Pattern cty.Value
   243  		Want    cty.Value
   244  		Err     bool
   245  	}{
   246  		{
   247  			cty.StringVal("."),
   248  			cty.StringVal("testdata*"),
   249  			cty.SetValEmpty(cty.String),
   250  			false,
   251  		},
   252  		{
   253  			cty.StringVal("."),
   254  			cty.StringVal("testdata"),
   255  			cty.SetValEmpty(cty.String),
   256  			false,
   257  		},
   258  		{
   259  			cty.StringVal("."),
   260  			cty.StringVal("{testdata,missing}"),
   261  			cty.SetValEmpty(cty.String),
   262  			false,
   263  		},
   264  		{
   265  			cty.StringVal("."),
   266  			cty.StringVal("testdata/missing"),
   267  			cty.SetValEmpty(cty.String),
   268  			false,
   269  		},
   270  		{
   271  			cty.StringVal("."),
   272  			cty.StringVal("testdata/missing*"),
   273  			cty.SetValEmpty(cty.String),
   274  			false,
   275  		},
   276  		{
   277  			cty.StringVal("."),
   278  			cty.StringVal("*/missing"),
   279  			cty.SetValEmpty(cty.String),
   280  			false,
   281  		},
   282  		{
   283  			cty.StringVal("."),
   284  			cty.StringVal("**/missing"),
   285  			cty.SetValEmpty(cty.String),
   286  			false,
   287  		},
   288  		{
   289  			cty.StringVal("."),
   290  			cty.StringVal("testdata/*.txt"),
   291  			cty.SetVal([]cty.Value{
   292  				cty.StringVal("testdata/hello.txt"),
   293  			}),
   294  			false,
   295  		},
   296  		{
   297  			cty.StringVal("."),
   298  			cty.StringVal("testdata/hello.txt"),
   299  			cty.SetVal([]cty.Value{
   300  				cty.StringVal("testdata/hello.txt"),
   301  			}),
   302  			false,
   303  		},
   304  		{
   305  			cty.StringVal("."),
   306  			cty.StringVal("testdata/hello.???"),
   307  			cty.SetVal([]cty.Value{
   308  				cty.StringVal("testdata/hello.txt"),
   309  			}),
   310  			false,
   311  		},
   312  		{
   313  			cty.StringVal("."),
   314  			cty.StringVal("testdata/hello*"),
   315  			cty.SetVal([]cty.Value{
   316  				cty.StringVal("testdata/hello.tmpl"),
   317  				cty.StringVal("testdata/hello.txt"),
   318  			}),
   319  			false,
   320  		},
   321  		{
   322  			cty.StringVal("."),
   323  			cty.StringVal("testdata/hello.{tmpl,txt}"),
   324  			cty.SetVal([]cty.Value{
   325  				cty.StringVal("testdata/hello.tmpl"),
   326  				cty.StringVal("testdata/hello.txt"),
   327  			}),
   328  			false,
   329  		},
   330  		{
   331  			cty.StringVal("."),
   332  			cty.StringVal("*/hello.txt"),
   333  			cty.SetVal([]cty.Value{
   334  				cty.StringVal("testdata/hello.txt"),
   335  			}),
   336  			false,
   337  		},
   338  		{
   339  			cty.StringVal("."),
   340  			cty.StringVal("*/*.txt"),
   341  			cty.SetVal([]cty.Value{
   342  				cty.StringVal("testdata/hello.txt"),
   343  			}),
   344  			false,
   345  		},
   346  		{
   347  			cty.StringVal("."),
   348  			cty.StringVal("*/hello*"),
   349  			cty.SetVal([]cty.Value{
   350  				cty.StringVal("testdata/hello.tmpl"),
   351  				cty.StringVal("testdata/hello.txt"),
   352  			}),
   353  			false,
   354  		},
   355  		{
   356  			cty.StringVal("."),
   357  			cty.StringVal("**/hello*"),
   358  			cty.SetVal([]cty.Value{
   359  				cty.StringVal("testdata/hello.tmpl"),
   360  				cty.StringVal("testdata/hello.txt"),
   361  			}),
   362  			false,
   363  		},
   364  		{
   365  			cty.StringVal("."),
   366  			cty.StringVal("**/hello.{tmpl,txt}"),
   367  			cty.SetVal([]cty.Value{
   368  				cty.StringVal("testdata/hello.tmpl"),
   369  				cty.StringVal("testdata/hello.txt"),
   370  			}),
   371  			false,
   372  		},
   373  		{
   374  			cty.StringVal("."),
   375  			cty.StringVal("["),
   376  			cty.SetValEmpty(cty.String),
   377  			true,
   378  		},
   379  		{
   380  			cty.StringVal("."),
   381  			cty.StringVal("\\"),
   382  			cty.SetValEmpty(cty.String),
   383  			true,
   384  		},
   385  		{
   386  			cty.StringVal("testdata"),
   387  			cty.StringVal("missing"),
   388  			cty.SetValEmpty(cty.String),
   389  			false,
   390  		},
   391  		{
   392  			cty.StringVal("testdata"),
   393  			cty.StringVal("missing*"),
   394  			cty.SetValEmpty(cty.String),
   395  			false,
   396  		},
   397  		{
   398  			cty.StringVal("testdata"),
   399  			cty.StringVal("*.txt"),
   400  			cty.SetVal([]cty.Value{
   401  				cty.StringVal("hello.txt"),
   402  			}),
   403  			false,
   404  		},
   405  		{
   406  			cty.StringVal("testdata"),
   407  			cty.StringVal("hello.txt"),
   408  			cty.SetVal([]cty.Value{
   409  				cty.StringVal("hello.txt"),
   410  			}),
   411  			false,
   412  		},
   413  		{
   414  			cty.StringVal("testdata"),
   415  			cty.StringVal("hello.???"),
   416  			cty.SetVal([]cty.Value{
   417  				cty.StringVal("hello.txt"),
   418  			}),
   419  			false,
   420  		},
   421  		{
   422  			cty.StringVal("testdata"),
   423  			cty.StringVal("hello*"),
   424  			cty.SetVal([]cty.Value{
   425  				cty.StringVal("hello.tmpl"),
   426  				cty.StringVal("hello.txt"),
   427  			}),
   428  			false,
   429  		},
   430  	}
   431  
   432  	for _, test := range tests {
   433  		t.Run(fmt.Sprintf("FileSet(\".\", %#v, %#v)", test.Path, test.Pattern), func(t *testing.T) {
   434  			got, err := FileSet(".", test.Path, test.Pattern)
   435  
   436  			if test.Err {
   437  				if err == nil {
   438  					t.Fatal("succeeded; want error")
   439  				}
   440  				return
   441  			} else if err != nil {
   442  				t.Fatalf("unexpected error: %s", err)
   443  			}
   444  
   445  			if !got.RawEquals(test.Want) {
   446  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   447  			}
   448  		})
   449  	}
   450  }
   451  
   452  func TestFileBase64(t *testing.T) {
   453  	tests := []struct {
   454  		Path cty.Value
   455  		Want cty.Value
   456  		Err  bool
   457  	}{
   458  		{
   459  			cty.StringVal("testdata/hello.txt"),
   460  			cty.StringVal("SGVsbG8gV29ybGQ="),
   461  			false,
   462  		},
   463  		{
   464  			cty.StringVal("testdata/icon.png"),
   465  			cty.StringVal("iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAq1BMVEX///9cTuVeUeRcTuZcTuZcT+VbSe1cTuVdT+MAAP9JSbZcT+VcTuZAQLFAQLJcTuVcTuZcUuBBQbA/P7JAQLJaTuRcT+RcTuVGQ7xAQLJVVf9cTuVcTuVGRMFeUeRbTeJcTuU/P7JeTeZbTOVcTeZAQLJBQbNAQLNaUORcTeZbT+VcTuRAQLNAQLRdTuRHR8xgUOdgUN9cTuVdTeRdT+VZTulcTuVAQLL///8+GmETAAAANnRSTlMApibw+osO6DcBB3fIX87+oRk3yehB0/Nj/gNs7nsTRv3dHmu//JYUMLVr3bssjxkgEK5CaxeK03nIAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAADoQAAA6EBvJf9gwAAAAd0SU1FB+EEBRIQDxZNTKsAAACCSURBVBjTfc7JFsFQEATQQpCYxyBEzJ55rvf/f0ZHcyQLvelTd1GngEwWycs5+UISyKLraSi9geWKK9Gr1j7AeqOJVtt2XtD1Bchef2BjQDAcCTC0CsA4mihMtXw2XwgsV2sFw812F+4P3y2GdI6nn3FGSs//4HJNAXDzU4Dg/oj/E+bsEbhf5cMsAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA0LTA1VDE4OjE2OjE1KzAyOjAws5bLVQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNC0wNVQxODoxNjoxNSswMjowMMLLc+kAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAC3RFWHRUaXRsZQBHcm91cJYfIowAAABXelRYdFJhdyBwcm9maWxlIHR5cGUgaXB0YwAAeJzj8gwIcVYoKMpPy8xJ5VIAAyMLLmMLEyMTS5MUAxMgRIA0w2QDI7NUIMvY1MjEzMQcxAfLgEigSi4A6hcRdPJCNZUAAAAASUVORK5CYII="),
   466  			false,
   467  		},
   468  		{
   469  			cty.StringVal("testdata/missing"),
   470  			cty.NilVal,
   471  			true, // no file exists
   472  		},
   473  	}
   474  
   475  	for _, test := range tests {
   476  		t.Run(fmt.Sprintf("FileBase64(\".\", %#v)", test.Path), func(t *testing.T) {
   477  			got, err := FileBase64(".", test.Path)
   478  
   479  			if test.Err {
   480  				if err == nil {
   481  					t.Fatal("succeeded; want error")
   482  				}
   483  				return
   484  			} else if err != nil {
   485  				t.Fatalf("unexpected error: %s", err)
   486  			}
   487  
   488  			if !got.RawEquals(test.Want) {
   489  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   490  			}
   491  		})
   492  	}
   493  }
   494  
   495  func TestBasename(t *testing.T) {
   496  	tests := []struct {
   497  		Path cty.Value
   498  		Want cty.Value
   499  		Err  bool
   500  	}{
   501  		{
   502  			cty.StringVal("testdata/hello.txt"),
   503  			cty.StringVal("hello.txt"),
   504  			false,
   505  		},
   506  		{
   507  			cty.StringVal("hello.txt"),
   508  			cty.StringVal("hello.txt"),
   509  			false,
   510  		},
   511  		{
   512  			cty.StringVal(""),
   513  			cty.StringVal("."),
   514  			false,
   515  		},
   516  	}
   517  
   518  	for _, test := range tests {
   519  		t.Run(fmt.Sprintf("Basename(%#v)", test.Path), func(t *testing.T) {
   520  			got, err := Basename(test.Path)
   521  
   522  			if test.Err {
   523  				if err == nil {
   524  					t.Fatal("succeeded; want error")
   525  				}
   526  				return
   527  			} else if err != nil {
   528  				t.Fatalf("unexpected error: %s", err)
   529  			}
   530  
   531  			if !got.RawEquals(test.Want) {
   532  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   533  			}
   534  		})
   535  	}
   536  }
   537  
   538  func TestDirname(t *testing.T) {
   539  	tests := []struct {
   540  		Path cty.Value
   541  		Want cty.Value
   542  		Err  bool
   543  	}{
   544  		{
   545  			cty.StringVal("testdata/hello.txt"),
   546  			cty.StringVal("testdata"),
   547  			false,
   548  		},
   549  		{
   550  			cty.StringVal("testdata/foo/hello.txt"),
   551  			cty.StringVal("testdata/foo"),
   552  			false,
   553  		},
   554  		{
   555  			cty.StringVal("hello.txt"),
   556  			cty.StringVal("."),
   557  			false,
   558  		},
   559  		{
   560  			cty.StringVal(""),
   561  			cty.StringVal("."),
   562  			false,
   563  		},
   564  	}
   565  
   566  	for _, test := range tests {
   567  		t.Run(fmt.Sprintf("Dirname(%#v)", test.Path), func(t *testing.T) {
   568  			got, err := Dirname(test.Path)
   569  
   570  			if test.Err {
   571  				if err == nil {
   572  					t.Fatal("succeeded; want error")
   573  				}
   574  				return
   575  			} else if err != nil {
   576  				t.Fatalf("unexpected error: %s", err)
   577  			}
   578  
   579  			if !got.RawEquals(test.Want) {
   580  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   581  			}
   582  		})
   583  	}
   584  }
   585  
   586  func TestPathExpand(t *testing.T) {
   587  	homePath, err := homedir.Dir()
   588  	if err != nil {
   589  		t.Fatalf("Error getting home directory: %v", err)
   590  	}
   591  
   592  	tests := []struct {
   593  		Path cty.Value
   594  		Want cty.Value
   595  		Err  bool
   596  	}{
   597  		{
   598  			cty.StringVal("~/test-file"),
   599  			cty.StringVal(filepath.Join(homePath, "test-file")),
   600  			false,
   601  		},
   602  		{
   603  			cty.StringVal("~/another/test/file"),
   604  			cty.StringVal(filepath.Join(homePath, "another/test/file")),
   605  			false,
   606  		},
   607  		{
   608  			cty.StringVal("/root/file"),
   609  			cty.StringVal("/root/file"),
   610  			false,
   611  		},
   612  		{
   613  			cty.StringVal("/"),
   614  			cty.StringVal("/"),
   615  			false,
   616  		},
   617  	}
   618  
   619  	for _, test := range tests {
   620  		t.Run(fmt.Sprintf("Dirname(%#v)", test.Path), func(t *testing.T) {
   621  			got, err := Pathexpand(test.Path)
   622  
   623  			if test.Err {
   624  				if err == nil {
   625  					t.Fatal("succeeded; want error")
   626  				}
   627  				return
   628  			} else if err != nil {
   629  				t.Fatalf("unexpected error: %s", err)
   630  			}
   631  
   632  			if !got.RawEquals(test.Want) {
   633  				t.Errorf("wrong result\ngot:  %#v\nwant: %#v", got, test.Want)
   634  			}
   635  		})
   636  	}
   637  }