github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/config/interpolate_funcs_test.go (about)

     1  package config
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"reflect"
     8  	"testing"
     9  	"time"
    10  
    11  	"path/filepath"
    12  
    13  	"github.com/hashicorp/hil"
    14  	"github.com/hashicorp/hil/ast"
    15  	"github.com/mitchellh/go-homedir"
    16  )
    17  
    18  func TestInterpolateFuncZipMap(t *testing.T) {
    19  	testFunction(t, testFunctionConfig{
    20  		Cases: []testFunctionCase{
    21  			{
    22  				`${zipmap(var.list, var.list2)}`,
    23  				map[string]interface{}{
    24  					"Hello": "bar",
    25  					"World": "baz",
    26  				},
    27  				false,
    28  			},
    29  			{
    30  				`${zipmap(var.list, var.nonstrings)}`,
    31  				map[string]interface{}{
    32  					"Hello": []interface{}{"bar", "baz"},
    33  					"World": []interface{}{"boo", "foo"},
    34  				},
    35  				false,
    36  			},
    37  			{
    38  				`${zipmap(var.nonstrings, var.list2)}`,
    39  				nil,
    40  				true,
    41  			},
    42  			{
    43  				`${zipmap(var.list, var.differentlengthlist)}`,
    44  				nil,
    45  				true,
    46  			},
    47  		},
    48  		Vars: map[string]ast.Variable{
    49  			"var.list": {
    50  				Type: ast.TypeList,
    51  				Value: []ast.Variable{
    52  					{
    53  						Type:  ast.TypeString,
    54  						Value: "Hello",
    55  					},
    56  					{
    57  						Type:  ast.TypeString,
    58  						Value: "World",
    59  					},
    60  				},
    61  			},
    62  			"var.list2": {
    63  				Type: ast.TypeList,
    64  				Value: []ast.Variable{
    65  					{
    66  						Type:  ast.TypeString,
    67  						Value: "bar",
    68  					},
    69  					{
    70  						Type:  ast.TypeString,
    71  						Value: "baz",
    72  					},
    73  				},
    74  			},
    75  			"var.differentlengthlist": {
    76  				Type: ast.TypeList,
    77  				Value: []ast.Variable{
    78  					{
    79  						Type:  ast.TypeString,
    80  						Value: "bar",
    81  					},
    82  					{
    83  						Type:  ast.TypeString,
    84  						Value: "baz",
    85  					},
    86  					{
    87  						Type:  ast.TypeString,
    88  						Value: "boo",
    89  					},
    90  				},
    91  			},
    92  			"var.nonstrings": {
    93  				Type: ast.TypeList,
    94  				Value: []ast.Variable{
    95  					{
    96  						Type: ast.TypeList,
    97  						Value: []ast.Variable{
    98  							{
    99  								Type:  ast.TypeString,
   100  								Value: "bar",
   101  							},
   102  							{
   103  								Type:  ast.TypeString,
   104  								Value: "baz",
   105  							},
   106  						},
   107  					},
   108  					{
   109  						Type: ast.TypeList,
   110  						Value: []ast.Variable{
   111  							{
   112  								Type:  ast.TypeString,
   113  								Value: "boo",
   114  							},
   115  							{
   116  								Type:  ast.TypeString,
   117  								Value: "foo",
   118  							},
   119  						},
   120  					},
   121  				},
   122  			},
   123  		},
   124  	})
   125  }
   126  
   127  func TestInterpolateFuncList(t *testing.T) {
   128  	testFunction(t, testFunctionConfig{
   129  		Cases: []testFunctionCase{
   130  			// empty input returns empty list
   131  			{
   132  				`${list()}`,
   133  				[]interface{}{},
   134  				false,
   135  			},
   136  
   137  			// single input returns list of length 1
   138  			{
   139  				`${list("hello")}`,
   140  				[]interface{}{"hello"},
   141  				false,
   142  			},
   143  
   144  			// two inputs returns list of length 2
   145  			{
   146  				`${list("hello", "world")}`,
   147  				[]interface{}{"hello", "world"},
   148  				false,
   149  			},
   150  
   151  			// not a string input gives error
   152  			{
   153  				`${list("hello", 42)}`,
   154  				nil,
   155  				true,
   156  			},
   157  
   158  			// list of lists
   159  			{
   160  				`${list("${var.list}", "${var.list2}")}`,
   161  				[]interface{}{[]interface{}{"Hello", "World"}, []interface{}{"bar", "baz"}},
   162  				false,
   163  			},
   164  
   165  			// list of maps
   166  			{
   167  				`${list("${var.map}", "${var.map2}")}`,
   168  				[]interface{}{map[string]interface{}{"key": "bar"}, map[string]interface{}{"key2": "baz"}},
   169  				false,
   170  			},
   171  
   172  			// error on a heterogeneous list
   173  			{
   174  				`${list("first", "${var.list}")}`,
   175  				nil,
   176  				true,
   177  			},
   178  		},
   179  		Vars: map[string]ast.Variable{
   180  			"var.list": {
   181  				Type: ast.TypeList,
   182  				Value: []ast.Variable{
   183  					{
   184  						Type:  ast.TypeString,
   185  						Value: "Hello",
   186  					},
   187  					{
   188  						Type:  ast.TypeString,
   189  						Value: "World",
   190  					},
   191  				},
   192  			},
   193  			"var.list2": {
   194  				Type: ast.TypeList,
   195  				Value: []ast.Variable{
   196  					{
   197  						Type:  ast.TypeString,
   198  						Value: "bar",
   199  					},
   200  					{
   201  						Type:  ast.TypeString,
   202  						Value: "baz",
   203  					},
   204  				},
   205  			},
   206  
   207  			"var.map": {
   208  				Type: ast.TypeMap,
   209  				Value: map[string]ast.Variable{
   210  					"key": {
   211  						Type:  ast.TypeString,
   212  						Value: "bar",
   213  					},
   214  				},
   215  			},
   216  			"var.map2": {
   217  				Type: ast.TypeMap,
   218  				Value: map[string]ast.Variable{
   219  					"key2": {
   220  						Type:  ast.TypeString,
   221  						Value: "baz",
   222  					},
   223  				},
   224  			},
   225  		},
   226  	})
   227  }
   228  
   229  func TestInterpolateFuncMax(t *testing.T) {
   230  	testFunction(t, testFunctionConfig{
   231  		Cases: []testFunctionCase{
   232  			{
   233  				`${max()}`,
   234  				nil,
   235  				true,
   236  			},
   237  
   238  			{
   239  				`${max("")}`,
   240  				nil,
   241  				true,
   242  			},
   243  
   244  			{
   245  				`${max(-1, 0, 1)}`,
   246  				"1",
   247  				false,
   248  			},
   249  
   250  			{
   251  				`${max(1, 0, -1)}`,
   252  				"1",
   253  				false,
   254  			},
   255  
   256  			{
   257  				`${max(-1, -2)}`,
   258  				"-1",
   259  				false,
   260  			},
   261  
   262  			{
   263  				`${max(-1)}`,
   264  				"-1",
   265  				false,
   266  			},
   267  		},
   268  	})
   269  }
   270  
   271  func TestInterpolateFuncMin(t *testing.T) {
   272  	testFunction(t, testFunctionConfig{
   273  		Cases: []testFunctionCase{
   274  			{
   275  				`${min()}`,
   276  				nil,
   277  				true,
   278  			},
   279  
   280  			{
   281  				`${min("")}`,
   282  				nil,
   283  				true,
   284  			},
   285  
   286  			{
   287  				`${min(-1, 0, 1)}`,
   288  				"-1",
   289  				false,
   290  			},
   291  
   292  			{
   293  				`${min(1, 0, -1)}`,
   294  				"-1",
   295  				false,
   296  			},
   297  
   298  			{
   299  				`${min(-1, -2)}`,
   300  				"-2",
   301  				false,
   302  			},
   303  
   304  			{
   305  				`${min(-1)}`,
   306  				"-1",
   307  				false,
   308  			},
   309  		},
   310  	})
   311  }
   312  
   313  func TestInterpolateFuncFloor(t *testing.T) {
   314  	testFunction(t, testFunctionConfig{
   315  		Cases: []testFunctionCase{
   316  			{
   317  				`${floor()}`,
   318  				nil,
   319  				true,
   320  			},
   321  
   322  			{
   323  				`${floor("")}`,
   324  				nil,
   325  				true,
   326  			},
   327  
   328  			{
   329  				`${floor("-1.3")}`, // there appears to be a AST bug where the parsed argument ends up being -1 without the "s
   330  				"-2",
   331  				false,
   332  			},
   333  
   334  			{
   335  				`${floor(1.7)}`,
   336  				"1",
   337  				false,
   338  			},
   339  		},
   340  	})
   341  }
   342  
   343  func TestInterpolateFuncCeil(t *testing.T) {
   344  	testFunction(t, testFunctionConfig{
   345  		Cases: []testFunctionCase{
   346  			{
   347  				`${ceil()}`,
   348  				nil,
   349  				true,
   350  			},
   351  
   352  			{
   353  				`${ceil("")}`,
   354  				nil,
   355  				true,
   356  			},
   357  
   358  			{
   359  				`${ceil(-1.8)}`,
   360  				"-1",
   361  				false,
   362  			},
   363  
   364  			{
   365  				`${ceil(1.2)}`,
   366  				"2",
   367  				false,
   368  			},
   369  		},
   370  	})
   371  }
   372  
   373  func TestInterpolateFuncMap(t *testing.T) {
   374  	testFunction(t, testFunctionConfig{
   375  		Cases: []testFunctionCase{
   376  			// empty input returns empty map
   377  			{
   378  				`${map()}`,
   379  				map[string]interface{}{},
   380  				false,
   381  			},
   382  
   383  			// odd args is error
   384  			{
   385  				`${map("odd")}`,
   386  				nil,
   387  				true,
   388  			},
   389  
   390  			// two args returns map w/ one k/v
   391  			{
   392  				`${map("hello", "world")}`,
   393  				map[string]interface{}{"hello": "world"},
   394  				false,
   395  			},
   396  
   397  			// four args get two k/v
   398  			{
   399  				`${map("hello", "world", "what's", "up?")}`,
   400  				map[string]interface{}{"hello": "world", "what's": "up?"},
   401  				false,
   402  			},
   403  
   404  			// map of lists is okay
   405  			{
   406  				`${map("hello", list("world"), "what's", list("up?"))}`,
   407  				map[string]interface{}{
   408  					"hello":  []interface{}{"world"},
   409  					"what's": []interface{}{"up?"},
   410  				},
   411  				false,
   412  			},
   413  
   414  			// map of maps is okay
   415  			{
   416  				`${map("hello", map("there", "world"), "what's", map("really", "up?"))}`,
   417  				map[string]interface{}{
   418  					"hello":  map[string]interface{}{"there": "world"},
   419  					"what's": map[string]interface{}{"really": "up?"},
   420  				},
   421  				false,
   422  			},
   423  
   424  			// keys have to be strings
   425  			{
   426  				`${map(list("listkey"), "val")}`,
   427  				nil,
   428  				true,
   429  			},
   430  
   431  			// types have to match
   432  			{
   433  				`${map("some", "strings", "also", list("lists"))}`,
   434  				nil,
   435  				true,
   436  			},
   437  
   438  			// duplicate keys are an error
   439  			{
   440  				`${map("key", "val", "key", "again")}`,
   441  				nil,
   442  				true,
   443  			},
   444  		},
   445  	})
   446  }
   447  
   448  func TestInterpolateFuncCompact(t *testing.T) {
   449  	testFunction(t, testFunctionConfig{
   450  		Cases: []testFunctionCase{
   451  			// empty string within array
   452  			{
   453  				`${compact(split(",", "a,,b"))}`,
   454  				[]interface{}{"a", "b"},
   455  				false,
   456  			},
   457  
   458  			// empty string at the end of array
   459  			{
   460  				`${compact(split(",", "a,b,"))}`,
   461  				[]interface{}{"a", "b"},
   462  				false,
   463  			},
   464  
   465  			// single empty string
   466  			{
   467  				`${compact(split(",", ""))}`,
   468  				[]interface{}{},
   469  				false,
   470  			},
   471  
   472  			// errrors on list of lists
   473  			{
   474  				`${compact(list(list("a"), list("b")))}`,
   475  				nil,
   476  				true,
   477  			},
   478  		},
   479  	})
   480  }
   481  
   482  func TestInterpolateFuncCidrHost(t *testing.T) {
   483  	testFunction(t, testFunctionConfig{
   484  		Cases: []testFunctionCase{
   485  			{
   486  				`${cidrhost("192.168.1.0/24", 5)}`,
   487  				"192.168.1.5",
   488  				false,
   489  			},
   490  			{
   491  				`${cidrhost("192.168.1.0/30", 255)}`,
   492  				nil,
   493  				true, // 255 doesn't fit in two bits
   494  			},
   495  			{
   496  				`${cidrhost("not-a-cidr", 6)}`,
   497  				nil,
   498  				true, // not a valid CIDR mask
   499  			},
   500  			{
   501  				`${cidrhost("10.256.0.0/8", 6)}`,
   502  				nil,
   503  				true, // can't have an octet >255
   504  			},
   505  		},
   506  	})
   507  }
   508  
   509  func TestInterpolateFuncCidrNetmask(t *testing.T) {
   510  	testFunction(t, testFunctionConfig{
   511  		Cases: []testFunctionCase{
   512  			{
   513  				`${cidrnetmask("192.168.1.0/24")}`,
   514  				"255.255.255.0",
   515  				false,
   516  			},
   517  			{
   518  				`${cidrnetmask("192.168.1.0/32")}`,
   519  				"255.255.255.255",
   520  				false,
   521  			},
   522  			{
   523  				`${cidrnetmask("0.0.0.0/0")}`,
   524  				"0.0.0.0",
   525  				false,
   526  			},
   527  			{
   528  				// This doesn't really make sense for IPv6 networks
   529  				// but it ought to do something sensible anyway.
   530  				`${cidrnetmask("1::/64")}`,
   531  				"ffff:ffff:ffff:ffff::",
   532  				false,
   533  			},
   534  			{
   535  				`${cidrnetmask("not-a-cidr")}`,
   536  				nil,
   537  				true, // not a valid CIDR mask
   538  			},
   539  			{
   540  				`${cidrnetmask("10.256.0.0/8")}`,
   541  				nil,
   542  				true, // can't have an octet >255
   543  			},
   544  		},
   545  	})
   546  }
   547  
   548  func TestInterpolateFuncCidrSubnet(t *testing.T) {
   549  	testFunction(t, testFunctionConfig{
   550  		Cases: []testFunctionCase{
   551  			{
   552  				`${cidrsubnet("192.168.2.0/20", 4, 6)}`,
   553  				"192.168.6.0/24",
   554  				false,
   555  			},
   556  			{
   557  				`${cidrsubnet("fe80::/48", 16, 6)}`,
   558  				"fe80:0:0:6::/64",
   559  				false,
   560  			},
   561  			{
   562  				// IPv4 address encoded in IPv6 syntax gets normalized
   563  				`${cidrsubnet("::ffff:192.168.0.0/112", 8, 6)}`,
   564  				"192.168.6.0/24",
   565  				false,
   566  			},
   567  			{
   568  				`${cidrsubnet("192.168.0.0/30", 4, 6)}`,
   569  				nil,
   570  				true, // not enough bits left
   571  			},
   572  			{
   573  				`${cidrsubnet("192.168.0.0/16", 2, 16)}`,
   574  				nil,
   575  				true, // can't encode 16 in 2 bits
   576  			},
   577  			{
   578  				`${cidrsubnet("not-a-cidr", 4, 6)}`,
   579  				nil,
   580  				true, // not a valid CIDR mask
   581  			},
   582  			{
   583  				`${cidrsubnet("10.256.0.0/8", 4, 6)}`,
   584  				nil,
   585  				true, // can't have an octet >255
   586  			},
   587  		},
   588  	})
   589  }
   590  
   591  func TestInterpolateFuncCoalesce(t *testing.T) {
   592  	testFunction(t, testFunctionConfig{
   593  		Cases: []testFunctionCase{
   594  			{
   595  				`${coalesce("first", "second", "third")}`,
   596  				"first",
   597  				false,
   598  			},
   599  			{
   600  				`${coalesce("", "second", "third")}`,
   601  				"second",
   602  				false,
   603  			},
   604  			{
   605  				`${coalesce("", "", "")}`,
   606  				"",
   607  				false,
   608  			},
   609  			{
   610  				`${coalesce("foo")}`,
   611  				nil,
   612  				true,
   613  			},
   614  		},
   615  	})
   616  }
   617  
   618  func TestInterpolateFuncConcat(t *testing.T) {
   619  	testFunction(t, testFunctionConfig{
   620  		Cases: []testFunctionCase{
   621  			// String + list
   622  			// no longer supported, now returns an error
   623  			{
   624  				`${concat("a", split(",", "b,c"))}`,
   625  				nil,
   626  				true,
   627  			},
   628  
   629  			// List + string
   630  			// no longer supported, now returns an error
   631  			{
   632  				`${concat(split(",", "a,b"), "c")}`,
   633  				nil,
   634  				true,
   635  			},
   636  
   637  			// Single list
   638  			{
   639  				`${concat(split(",", ",foo,"))}`,
   640  				[]interface{}{"", "foo", ""},
   641  				false,
   642  			},
   643  			{
   644  				`${concat(split(",", "a,b,c"))}`,
   645  				[]interface{}{"a", "b", "c"},
   646  				false,
   647  			},
   648  
   649  			// Two lists
   650  			{
   651  				`${concat(split(",", "a,b,c"), split(",", "d,e"))}`,
   652  				[]interface{}{"a", "b", "c", "d", "e"},
   653  				false,
   654  			},
   655  			// Two lists with different separators
   656  			{
   657  				`${concat(split(",", "a,b,c"), split(" ", "d e"))}`,
   658  				[]interface{}{"a", "b", "c", "d", "e"},
   659  				false,
   660  			},
   661  
   662  			// More lists
   663  			{
   664  				`${concat(split(",", "a,b"), split(",", "c,d"), split(",", "e,f"), split(",", "0,1"))}`,
   665  				[]interface{}{"a", "b", "c", "d", "e", "f", "0", "1"},
   666  				false,
   667  			},
   668  
   669  			// list vars
   670  			{
   671  				`${concat("${var.list}", "${var.list}")}`,
   672  				[]interface{}{"a", "b", "a", "b"},
   673  				false,
   674  			},
   675  			// lists of lists
   676  			{
   677  				`${concat("${var.lists}", "${var.lists}")}`,
   678  				[]interface{}{[]interface{}{"c", "d"}, []interface{}{"c", "d"}},
   679  				false,
   680  			},
   681  
   682  			// lists of maps
   683  			{
   684  				`${concat("${var.maps}", "${var.maps}")}`,
   685  				[]interface{}{map[string]interface{}{"key1": "a", "key2": "b"}, map[string]interface{}{"key1": "a", "key2": "b"}},
   686  				false,
   687  			},
   688  
   689  			// multiple strings
   690  			// no longer supported, now returns an error
   691  			{
   692  				`${concat("string1", "string2")}`,
   693  				nil,
   694  				true,
   695  			},
   696  
   697  			// mismatched types
   698  			{
   699  				`${concat("${var.lists}", "${var.maps}")}`,
   700  				nil,
   701  				true,
   702  			},
   703  		},
   704  		Vars: map[string]ast.Variable{
   705  			"var.list": {
   706  				Type: ast.TypeList,
   707  				Value: []ast.Variable{
   708  					{
   709  						Type:  ast.TypeString,
   710  						Value: "a",
   711  					},
   712  					{
   713  						Type:  ast.TypeString,
   714  						Value: "b",
   715  					},
   716  				},
   717  			},
   718  			"var.lists": {
   719  				Type: ast.TypeList,
   720  				Value: []ast.Variable{
   721  					{
   722  						Type: ast.TypeList,
   723  						Value: []ast.Variable{
   724  							{
   725  								Type:  ast.TypeString,
   726  								Value: "c",
   727  							},
   728  							{
   729  								Type:  ast.TypeString,
   730  								Value: "d",
   731  							},
   732  						},
   733  					},
   734  				},
   735  			},
   736  			"var.maps": {
   737  				Type: ast.TypeList,
   738  				Value: []ast.Variable{
   739  					{
   740  						Type: ast.TypeMap,
   741  						Value: map[string]ast.Variable{
   742  							"key1": {
   743  								Type:  ast.TypeString,
   744  								Value: "a",
   745  							},
   746  							"key2": {
   747  								Type:  ast.TypeString,
   748  								Value: "b",
   749  							},
   750  						},
   751  					},
   752  				},
   753  			},
   754  		},
   755  	})
   756  }
   757  
   758  func TestInterpolateFuncMerge(t *testing.T) {
   759  	testFunction(t, testFunctionConfig{
   760  		Cases: []testFunctionCase{
   761  			// basic merge
   762  			{
   763  				`${merge(map("a", "b"), map("c", "d"))}`,
   764  				map[string]interface{}{"a": "b", "c": "d"},
   765  				false,
   766  			},
   767  
   768  			// merge with conflicts is ok, last in wins.
   769  			{
   770  				`${merge(map("a", "b", "c", "X"), map("c", "d"))}`,
   771  				map[string]interface{}{"a": "b", "c": "d"},
   772  				false,
   773  			},
   774  
   775  			// merge variadic
   776  			{
   777  				`${merge(map("a", "b"), map("c", "d"), map("e", "f"))}`,
   778  				map[string]interface{}{"a": "b", "c": "d", "e": "f"},
   779  				false,
   780  			},
   781  
   782  			// merge with variables
   783  			{
   784  				`${merge(var.maps[0], map("c", "d"))}`,
   785  				map[string]interface{}{"key1": "a", "key2": "b", "c": "d"},
   786  				false,
   787  			},
   788  
   789  			// only accept maps
   790  			{
   791  				`${merge(map("a", "b"), list("c", "d"))}`,
   792  				nil,
   793  				true,
   794  			},
   795  
   796  			// merge maps of maps
   797  			{
   798  				`${merge(map("a", var.maps[0]), map("b", var.maps[1]))}`,
   799  				map[string]interface{}{
   800  					"b": map[string]interface{}{"key3": "d", "key4": "c"},
   801  					"a": map[string]interface{}{"key1": "a", "key2": "b"},
   802  				},
   803  				false,
   804  			},
   805  			// merge maps of lists
   806  			{
   807  				`${merge(map("a", list("b")), map("c", list("d", "e")))}`,
   808  				map[string]interface{}{"a": []interface{}{"b"}, "c": []interface{}{"d", "e"}},
   809  				false,
   810  			},
   811  			// merge map of various kinds
   812  			{
   813  				`${merge(map("a", var.maps[0]), map("b", list("c", "d")))}`,
   814  				map[string]interface{}{"a": map[string]interface{}{"key1": "a", "key2": "b"}, "b": []interface{}{"c", "d"}},
   815  				false,
   816  			},
   817  		},
   818  		Vars: map[string]ast.Variable{
   819  			"var.maps": {
   820  				Type: ast.TypeList,
   821  				Value: []ast.Variable{
   822  					{
   823  						Type: ast.TypeMap,
   824  						Value: map[string]ast.Variable{
   825  							"key1": {
   826  								Type:  ast.TypeString,
   827  								Value: "a",
   828  							},
   829  							"key2": {
   830  								Type:  ast.TypeString,
   831  								Value: "b",
   832  							},
   833  						},
   834  					},
   835  					{
   836  						Type: ast.TypeMap,
   837  						Value: map[string]ast.Variable{
   838  							"key3": {
   839  								Type:  ast.TypeString,
   840  								Value: "d",
   841  							},
   842  							"key4": {
   843  								Type:  ast.TypeString,
   844  								Value: "c",
   845  							},
   846  						},
   847  					},
   848  				},
   849  			},
   850  		},
   851  	})
   852  
   853  }
   854  
   855  func TestInterpolateFuncDistinct(t *testing.T) {
   856  	testFunction(t, testFunctionConfig{
   857  		Cases: []testFunctionCase{
   858  			// 3 duplicates
   859  			{
   860  				`${distinct(concat(split(",", "user1,user2,user3"), split(",", "user1,user2,user3")))}`,
   861  				[]interface{}{"user1", "user2", "user3"},
   862  				false,
   863  			},
   864  			// 1 duplicate
   865  			{
   866  				`${distinct(concat(split(",", "user1,user2,user3"), split(",", "user1,user4")))}`,
   867  				[]interface{}{"user1", "user2", "user3", "user4"},
   868  				false,
   869  			},
   870  			// too many args
   871  			{
   872  				`${distinct(concat(split(",", "user1,user2,user3"), split(",", "user1,user4")), "foo")}`,
   873  				nil,
   874  				true,
   875  			},
   876  			// non-flat list is an error
   877  			{
   878  				`${distinct(list(list("a"), list("a")))}`,
   879  				nil,
   880  				true,
   881  			},
   882  		},
   883  	})
   884  }
   885  
   886  func TestInterpolateFuncFile(t *testing.T) {
   887  	tf, err := ioutil.TempFile("", "tf")
   888  	if err != nil {
   889  		t.Fatalf("err: %s", err)
   890  	}
   891  	path := tf.Name()
   892  	tf.Write([]byte("foo"))
   893  	tf.Close()
   894  	defer os.Remove(path)
   895  
   896  	testFunction(t, testFunctionConfig{
   897  		Cases: []testFunctionCase{
   898  			{
   899  				fmt.Sprintf(`${file("%s")}`, path),
   900  				"foo",
   901  				false,
   902  			},
   903  
   904  			// Invalid path
   905  			{
   906  				`${file("/i/dont/exist")}`,
   907  				nil,
   908  				true,
   909  			},
   910  
   911  			// Too many args
   912  			{
   913  				`${file("foo", "bar")}`,
   914  				nil,
   915  				true,
   916  			},
   917  		},
   918  	})
   919  }
   920  
   921  func TestInterpolateFuncFormat(t *testing.T) {
   922  	testFunction(t, testFunctionConfig{
   923  		Cases: []testFunctionCase{
   924  			{
   925  				`${format("hello")}`,
   926  				"hello",
   927  				false,
   928  			},
   929  
   930  			{
   931  				`${format("hello %s", "world")}`,
   932  				"hello world",
   933  				false,
   934  			},
   935  
   936  			{
   937  				`${format("hello %d", 42)}`,
   938  				"hello 42",
   939  				false,
   940  			},
   941  
   942  			{
   943  				`${format("hello %05d", 42)}`,
   944  				"hello 00042",
   945  				false,
   946  			},
   947  
   948  			{
   949  				`${format("hello %05d", 12345)}`,
   950  				"hello 12345",
   951  				false,
   952  			},
   953  		},
   954  	})
   955  }
   956  
   957  func TestInterpolateFuncFormatList(t *testing.T) {
   958  	testFunction(t, testFunctionConfig{
   959  		Cases: []testFunctionCase{
   960  			// formatlist requires at least one list
   961  			{
   962  				`${formatlist("hello")}`,
   963  				nil,
   964  				true,
   965  			},
   966  			{
   967  				`${formatlist("hello %s", "world")}`,
   968  				nil,
   969  				true,
   970  			},
   971  			// formatlist applies to each list element in turn
   972  			{
   973  				`${formatlist("<%s>", split(",", "A,B"))}`,
   974  				[]interface{}{"<A>", "<B>"},
   975  				false,
   976  			},
   977  			// formatlist repeats scalar elements
   978  			{
   979  				`${join(", ", formatlist("%s=%s", "x", split(",", "A,B,C")))}`,
   980  				"x=A, x=B, x=C",
   981  				false,
   982  			},
   983  			// Multiple lists are walked in parallel
   984  			{
   985  				`${join(", ", formatlist("%s=%s", split(",", "A,B,C"), split(",", "1,2,3")))}`,
   986  				"A=1, B=2, C=3",
   987  				false,
   988  			},
   989  			// Mismatched list lengths generate an error
   990  			{
   991  				`${formatlist("%s=%2s", split(",", "A,B,C,D"), split(",", "1,2,3"))}`,
   992  				nil,
   993  				true,
   994  			},
   995  			// Works with lists of length 1 [GH-2240]
   996  			{
   997  				`${formatlist("%s.id", split(",", "demo-rest-elb"))}`,
   998  				[]interface{}{"demo-rest-elb.id"},
   999  				false,
  1000  			},
  1001  			// Works with empty lists [GH-7607]
  1002  			{
  1003  				`${formatlist("%s", var.emptylist)}`,
  1004  				[]interface{}{},
  1005  				false,
  1006  			},
  1007  		},
  1008  		Vars: map[string]ast.Variable{
  1009  			"var.emptylist": {
  1010  				Type:  ast.TypeList,
  1011  				Value: []ast.Variable{},
  1012  			},
  1013  		},
  1014  	})
  1015  }
  1016  
  1017  func TestInterpolateFuncIndex(t *testing.T) {
  1018  	testFunction(t, testFunctionConfig{
  1019  		Vars: map[string]ast.Variable{
  1020  			"var.list1": interfaceToVariableSwallowError([]string{"notfoo", "stillnotfoo", "bar"}),
  1021  			"var.list2": interfaceToVariableSwallowError([]string{"foo"}),
  1022  			"var.list3": interfaceToVariableSwallowError([]string{"foo", "spam", "bar", "eggs"}),
  1023  		},
  1024  		Cases: []testFunctionCase{
  1025  			{
  1026  				`${index("test", "")}`,
  1027  				nil,
  1028  				true,
  1029  			},
  1030  
  1031  			{
  1032  				`${index(var.list1, "foo")}`,
  1033  				nil,
  1034  				true,
  1035  			},
  1036  
  1037  			{
  1038  				`${index(var.list2, "foo")}`,
  1039  				"0",
  1040  				false,
  1041  			},
  1042  
  1043  			{
  1044  				`${index(var.list3, "bar")}`,
  1045  				"2",
  1046  				false,
  1047  			},
  1048  		},
  1049  	})
  1050  }
  1051  
  1052  func TestInterpolateFuncJoin(t *testing.T) {
  1053  	testFunction(t, testFunctionConfig{
  1054  		Vars: map[string]ast.Variable{
  1055  			"var.a_list":        interfaceToVariableSwallowError([]string{"foo"}),
  1056  			"var.a_longer_list": interfaceToVariableSwallowError([]string{"foo", "bar", "baz"}),
  1057  			"var.list_of_lists": interfaceToVariableSwallowError([]interface{}{[]string{"foo"}, []string{"bar"}, []string{"baz"}}),
  1058  		},
  1059  		Cases: []testFunctionCase{
  1060  			{
  1061  				`${join(",")}`,
  1062  				nil,
  1063  				true,
  1064  			},
  1065  
  1066  			{
  1067  				`${join(",", var.a_list)}`,
  1068  				"foo",
  1069  				false,
  1070  			},
  1071  
  1072  			{
  1073  				`${join(".", var.a_longer_list)}`,
  1074  				"foo.bar.baz",
  1075  				false,
  1076  			},
  1077  
  1078  			{
  1079  				`${join(".", var.list_of_lists)}`,
  1080  				nil,
  1081  				true,
  1082  			},
  1083  			{
  1084  				`${join(".", list(list("nested")))}`,
  1085  				nil,
  1086  				true,
  1087  			},
  1088  		},
  1089  	})
  1090  }
  1091  
  1092  func TestInterpolateFuncJSONEncode(t *testing.T) {
  1093  	testFunction(t, testFunctionConfig{
  1094  		Vars: map[string]ast.Variable{
  1095  			"easy": ast.Variable{
  1096  				Value: "test",
  1097  				Type:  ast.TypeString,
  1098  			},
  1099  			"hard": ast.Variable{
  1100  				Value: " foo \\ \n \t \" bar ",
  1101  				Type:  ast.TypeString,
  1102  			},
  1103  			"list": interfaceToVariableSwallowError([]string{"foo", "bar\tbaz"}),
  1104  			// XXX can't use InterfaceToVariable as it converts empty slice into empty
  1105  			// map.
  1106  			"emptylist": ast.Variable{
  1107  				Value: []ast.Variable{},
  1108  				Type:  ast.TypeList,
  1109  			},
  1110  			"map": interfaceToVariableSwallowError(map[string]string{
  1111  				"foo":     "bar",
  1112  				"ba \n z": "q\\x",
  1113  			}),
  1114  			"emptymap": interfaceToVariableSwallowError(map[string]string{}),
  1115  
  1116  			// Not yet supported (but it would be nice)
  1117  			"nestedlist": interfaceToVariableSwallowError([][]string{{"foo"}}),
  1118  			"nestedmap":  interfaceToVariableSwallowError(map[string][]string{"foo": {"bar"}}),
  1119  		},
  1120  		Cases: []testFunctionCase{
  1121  			{
  1122  				`${jsonencode("test")}`,
  1123  				`"test"`,
  1124  				false,
  1125  			},
  1126  			{
  1127  				`${jsonencode(easy)}`,
  1128  				`"test"`,
  1129  				false,
  1130  			},
  1131  			{
  1132  				`${jsonencode(hard)}`,
  1133  				`" foo \\ \n \t \" bar "`,
  1134  				false,
  1135  			},
  1136  			{
  1137  				`${jsonencode("")}`,
  1138  				`""`,
  1139  				false,
  1140  			},
  1141  			{
  1142  				`${jsonencode()}`,
  1143  				nil,
  1144  				true,
  1145  			},
  1146  			{
  1147  				`${jsonencode(list)}`,
  1148  				`["foo","bar\tbaz"]`,
  1149  				false,
  1150  			},
  1151  			{
  1152  				`${jsonencode(emptylist)}`,
  1153  				`[]`,
  1154  				false,
  1155  			},
  1156  			{
  1157  				`${jsonencode(map)}`,
  1158  				`{"ba \n z":"q\\x","foo":"bar"}`,
  1159  				false,
  1160  			},
  1161  			{
  1162  				`${jsonencode(emptymap)}`,
  1163  				`{}`,
  1164  				false,
  1165  			},
  1166  			{
  1167  				`${jsonencode(nestedlist)}`,
  1168  				nil,
  1169  				true,
  1170  			},
  1171  			{
  1172  				`${jsonencode(nestedmap)}`,
  1173  				nil,
  1174  				true,
  1175  			},
  1176  		},
  1177  	})
  1178  }
  1179  
  1180  func TestInterpolateFuncReplace(t *testing.T) {
  1181  	testFunction(t, testFunctionConfig{
  1182  		Cases: []testFunctionCase{
  1183  			// Regular search and replace
  1184  			{
  1185  				`${replace("hello", "hel", "bel")}`,
  1186  				"bello",
  1187  				false,
  1188  			},
  1189  
  1190  			// Search string doesn't match
  1191  			{
  1192  				`${replace("hello", "nope", "bel")}`,
  1193  				"hello",
  1194  				false,
  1195  			},
  1196  
  1197  			// Regular expression
  1198  			{
  1199  				`${replace("hello", "/l/", "L")}`,
  1200  				"heLLo",
  1201  				false,
  1202  			},
  1203  
  1204  			{
  1205  				`${replace("helo", "/(l)/", "$1$1")}`,
  1206  				"hello",
  1207  				false,
  1208  			},
  1209  
  1210  			// Bad regexp
  1211  			{
  1212  				`${replace("helo", "/(l/", "$1$1")}`,
  1213  				nil,
  1214  				true,
  1215  			},
  1216  		},
  1217  	})
  1218  }
  1219  
  1220  func TestInterpolateFuncLength(t *testing.T) {
  1221  	testFunction(t, testFunctionConfig{
  1222  		Cases: []testFunctionCase{
  1223  			// Raw strings
  1224  			{
  1225  				`${length("")}`,
  1226  				"0",
  1227  				false,
  1228  			},
  1229  			{
  1230  				`${length("a")}`,
  1231  				"1",
  1232  				false,
  1233  			},
  1234  			{
  1235  				`${length(" ")}`,
  1236  				"1",
  1237  				false,
  1238  			},
  1239  			{
  1240  				`${length(" a ,")}`,
  1241  				"4",
  1242  				false,
  1243  			},
  1244  			{
  1245  				`${length("aaa")}`,
  1246  				"3",
  1247  				false,
  1248  			},
  1249  
  1250  			// Lists
  1251  			{
  1252  				`${length(split(",", "a"))}`,
  1253  				"1",
  1254  				false,
  1255  			},
  1256  			{
  1257  				`${length(split(",", "foo,"))}`,
  1258  				"2",
  1259  				false,
  1260  			},
  1261  			{
  1262  				`${length(split(",", ",foo,"))}`,
  1263  				"3",
  1264  				false,
  1265  			},
  1266  			{
  1267  				`${length(split(",", "foo,bar"))}`,
  1268  				"2",
  1269  				false,
  1270  			},
  1271  			{
  1272  				`${length(split(".", "one.two.three.four.five"))}`,
  1273  				"5",
  1274  				false,
  1275  			},
  1276  			// Want length 0 if we split an empty string then compact
  1277  			{
  1278  				`${length(compact(split(",", "")))}`,
  1279  				"0",
  1280  				false,
  1281  			},
  1282  			// Works for maps
  1283  			{
  1284  				`${length(map("k", "v"))}`,
  1285  				"1",
  1286  				false,
  1287  			},
  1288  			{
  1289  				`${length(map("k1", "v1", "k2", "v2"))}`,
  1290  				"2",
  1291  				false,
  1292  			},
  1293  		},
  1294  	})
  1295  }
  1296  
  1297  func TestInterpolateFuncSignum(t *testing.T) {
  1298  	testFunction(t, testFunctionConfig{
  1299  		Cases: []testFunctionCase{
  1300  			{
  1301  				`${signum()}`,
  1302  				nil,
  1303  				true,
  1304  			},
  1305  
  1306  			{
  1307  				`${signum("")}`,
  1308  				nil,
  1309  				true,
  1310  			},
  1311  
  1312  			{
  1313  				`${signum(0)}`,
  1314  				"0",
  1315  				false,
  1316  			},
  1317  
  1318  			{
  1319  				`${signum(15)}`,
  1320  				"1",
  1321  				false,
  1322  			},
  1323  
  1324  			{
  1325  				`${signum(-29)}`,
  1326  				"-1",
  1327  				false,
  1328  			},
  1329  		},
  1330  	})
  1331  }
  1332  
  1333  func TestInterpolateFuncSlice(t *testing.T) {
  1334  	testFunction(t, testFunctionConfig{
  1335  		Cases: []testFunctionCase{
  1336  			// Negative from index
  1337  			{
  1338  				`${slice(list("a"), -1, 0)}`,
  1339  				nil,
  1340  				true,
  1341  			},
  1342  			// From index > to index
  1343  			{
  1344  				`${slice(list("a", "b", "c"), 2, 1)}`,
  1345  				nil,
  1346  				true,
  1347  			},
  1348  			// To index too large
  1349  			{
  1350  				`${slice(var.list_of_strings, 1, 4)}`,
  1351  				nil,
  1352  				true,
  1353  			},
  1354  			// Empty slice
  1355  			{
  1356  				`${slice(var.list_of_strings, 1, 1)}`,
  1357  				[]interface{}{},
  1358  				false,
  1359  			},
  1360  			{
  1361  				`${slice(var.list_of_strings, 1, 2)}`,
  1362  				[]interface{}{"b"},
  1363  				false,
  1364  			},
  1365  			{
  1366  				`${slice(var.list_of_strings, 0, length(var.list_of_strings) - 1)}`,
  1367  				[]interface{}{"a", "b"},
  1368  				false,
  1369  			},
  1370  		},
  1371  		Vars: map[string]ast.Variable{
  1372  			"var.list_of_strings": {
  1373  				Type: ast.TypeList,
  1374  				Value: []ast.Variable{
  1375  					{
  1376  						Type:  ast.TypeString,
  1377  						Value: "a",
  1378  					},
  1379  					{
  1380  						Type:  ast.TypeString,
  1381  						Value: "b",
  1382  					},
  1383  					{
  1384  						Type:  ast.TypeString,
  1385  						Value: "c",
  1386  					},
  1387  				},
  1388  			},
  1389  		},
  1390  	})
  1391  }
  1392  
  1393  func TestInterpolateFuncSort(t *testing.T) {
  1394  	testFunction(t, testFunctionConfig{
  1395  		Vars: map[string]ast.Variable{
  1396  			"var.strings": ast.Variable{
  1397  				Type: ast.TypeList,
  1398  				Value: []ast.Variable{
  1399  					{Type: ast.TypeString, Value: "c"},
  1400  					{Type: ast.TypeString, Value: "a"},
  1401  					{Type: ast.TypeString, Value: "b"},
  1402  				},
  1403  			},
  1404  			"var.notstrings": ast.Variable{
  1405  				Type: ast.TypeList,
  1406  				Value: []ast.Variable{
  1407  					{Type: ast.TypeList, Value: []ast.Variable{}},
  1408  					{Type: ast.TypeString, Value: "b"},
  1409  				},
  1410  			},
  1411  		},
  1412  		Cases: []testFunctionCase{
  1413  			{
  1414  				`${sort(var.strings)}`,
  1415  				[]interface{}{"a", "b", "c"},
  1416  				false,
  1417  			},
  1418  			{
  1419  				`${sort(var.notstrings)}`,
  1420  				nil,
  1421  				true,
  1422  			},
  1423  		},
  1424  	})
  1425  }
  1426  
  1427  func TestInterpolateFuncSplit(t *testing.T) {
  1428  	testFunction(t, testFunctionConfig{
  1429  		Cases: []testFunctionCase{
  1430  			{
  1431  				`${split(",")}`,
  1432  				nil,
  1433  				true,
  1434  			},
  1435  
  1436  			{
  1437  				`${split(",", "")}`,
  1438  				[]interface{}{""},
  1439  				false,
  1440  			},
  1441  
  1442  			{
  1443  				`${split(",", "foo")}`,
  1444  				[]interface{}{"foo"},
  1445  				false,
  1446  			},
  1447  
  1448  			{
  1449  				`${split(",", ",,,")}`,
  1450  				[]interface{}{"", "", "", ""},
  1451  				false,
  1452  			},
  1453  
  1454  			{
  1455  				`${split(",", "foo,")}`,
  1456  				[]interface{}{"foo", ""},
  1457  				false,
  1458  			},
  1459  
  1460  			{
  1461  				`${split(",", ",foo,")}`,
  1462  				[]interface{}{"", "foo", ""},
  1463  				false,
  1464  			},
  1465  
  1466  			{
  1467  				`${split(".", "foo.bar.baz")}`,
  1468  				[]interface{}{"foo", "bar", "baz"},
  1469  				false,
  1470  			},
  1471  		},
  1472  	})
  1473  }
  1474  
  1475  func TestInterpolateFuncLookup(t *testing.T) {
  1476  	testFunction(t, testFunctionConfig{
  1477  		Vars: map[string]ast.Variable{
  1478  			"var.foo": {
  1479  				Type: ast.TypeMap,
  1480  				Value: map[string]ast.Variable{
  1481  					"bar": {
  1482  						Type:  ast.TypeString,
  1483  						Value: "baz",
  1484  					},
  1485  				},
  1486  			},
  1487  			"var.map_of_lists": ast.Variable{
  1488  				Type: ast.TypeMap,
  1489  				Value: map[string]ast.Variable{
  1490  					"bar": {
  1491  						Type: ast.TypeList,
  1492  						Value: []ast.Variable{
  1493  							{
  1494  								Type:  ast.TypeString,
  1495  								Value: "baz",
  1496  							},
  1497  						},
  1498  					},
  1499  				},
  1500  			},
  1501  		},
  1502  		Cases: []testFunctionCase{
  1503  			{
  1504  				`${lookup(var.foo, "bar")}`,
  1505  				"baz",
  1506  				false,
  1507  			},
  1508  
  1509  			// Invalid key
  1510  			{
  1511  				`${lookup(var.foo, "baz")}`,
  1512  				nil,
  1513  				true,
  1514  			},
  1515  
  1516  			// Supplied default with valid key
  1517  			{
  1518  				`${lookup(var.foo, "bar", "")}`,
  1519  				"baz",
  1520  				false,
  1521  			},
  1522  
  1523  			// Supplied default with invalid key
  1524  			{
  1525  				`${lookup(var.foo, "zip", "")}`,
  1526  				"",
  1527  				false,
  1528  			},
  1529  
  1530  			// Too many args
  1531  			{
  1532  				`${lookup(var.foo, "bar", "", "abc")}`,
  1533  				nil,
  1534  				true,
  1535  			},
  1536  
  1537  			// Cannot lookup into map of lists
  1538  			{
  1539  				`${lookup(var.map_of_lists, "bar")}`,
  1540  				nil,
  1541  				true,
  1542  			},
  1543  
  1544  			// Non-empty default
  1545  			{
  1546  				`${lookup(var.foo, "zap", "xyz")}`,
  1547  				"xyz",
  1548  				false,
  1549  			},
  1550  		},
  1551  	})
  1552  }
  1553  
  1554  func TestInterpolateFuncKeys(t *testing.T) {
  1555  	testFunction(t, testFunctionConfig{
  1556  		Vars: map[string]ast.Variable{
  1557  			"var.foo": ast.Variable{
  1558  				Type: ast.TypeMap,
  1559  				Value: map[string]ast.Variable{
  1560  					"bar": ast.Variable{
  1561  						Value: "baz",
  1562  						Type:  ast.TypeString,
  1563  					},
  1564  					"qux": ast.Variable{
  1565  						Value: "quack",
  1566  						Type:  ast.TypeString,
  1567  					},
  1568  				},
  1569  			},
  1570  			"var.str": ast.Variable{
  1571  				Value: "astring",
  1572  				Type:  ast.TypeString,
  1573  			},
  1574  		},
  1575  		Cases: []testFunctionCase{
  1576  			{
  1577  				`${keys(var.foo)}`,
  1578  				[]interface{}{"bar", "qux"},
  1579  				false,
  1580  			},
  1581  
  1582  			// Invalid key
  1583  			{
  1584  				`${keys(var.not)}`,
  1585  				nil,
  1586  				true,
  1587  			},
  1588  
  1589  			// Too many args
  1590  			{
  1591  				`${keys(var.foo, "bar")}`,
  1592  				nil,
  1593  				true,
  1594  			},
  1595  
  1596  			// Not a map
  1597  			{
  1598  				`${keys(var.str)}`,
  1599  				nil,
  1600  				true,
  1601  			},
  1602  		},
  1603  	})
  1604  }
  1605  
  1606  // Confirm that keys return in sorted order, and values return in the order of
  1607  // their sorted keys.
  1608  func TestInterpolateFuncKeyValOrder(t *testing.T) {
  1609  	testFunction(t, testFunctionConfig{
  1610  		Vars: map[string]ast.Variable{
  1611  			"var.foo": ast.Variable{
  1612  				Type: ast.TypeMap,
  1613  				Value: map[string]ast.Variable{
  1614  					"D": ast.Variable{
  1615  						Value: "2",
  1616  						Type:  ast.TypeString,
  1617  					},
  1618  					"C": ast.Variable{
  1619  						Value: "Y",
  1620  						Type:  ast.TypeString,
  1621  					},
  1622  					"A": ast.Variable{
  1623  						Value: "X",
  1624  						Type:  ast.TypeString,
  1625  					},
  1626  					"10": ast.Variable{
  1627  						Value: "Z",
  1628  						Type:  ast.TypeString,
  1629  					},
  1630  					"1": ast.Variable{
  1631  						Value: "4",
  1632  						Type:  ast.TypeString,
  1633  					},
  1634  					"3": ast.Variable{
  1635  						Value: "W",
  1636  						Type:  ast.TypeString,
  1637  					},
  1638  				},
  1639  			},
  1640  		},
  1641  		Cases: []testFunctionCase{
  1642  			{
  1643  				`${keys(var.foo)}`,
  1644  				[]interface{}{"1", "10", "3", "A", "C", "D"},
  1645  				false,
  1646  			},
  1647  
  1648  			{
  1649  				`${values(var.foo)}`,
  1650  				[]interface{}{"4", "Z", "W", "X", "Y", "2"},
  1651  				false,
  1652  			},
  1653  		},
  1654  	})
  1655  }
  1656  
  1657  func TestInterpolateFuncValues(t *testing.T) {
  1658  	testFunction(t, testFunctionConfig{
  1659  		Vars: map[string]ast.Variable{
  1660  			"var.foo": ast.Variable{
  1661  				Type: ast.TypeMap,
  1662  				Value: map[string]ast.Variable{
  1663  					"bar": ast.Variable{
  1664  						Value: "quack",
  1665  						Type:  ast.TypeString,
  1666  					},
  1667  					"qux": ast.Variable{
  1668  						Value: "baz",
  1669  						Type:  ast.TypeString,
  1670  					},
  1671  				},
  1672  			},
  1673  			"var.str": ast.Variable{
  1674  				Value: "astring",
  1675  				Type:  ast.TypeString,
  1676  			},
  1677  		},
  1678  		Cases: []testFunctionCase{
  1679  			{
  1680  				`${values(var.foo)}`,
  1681  				[]interface{}{"quack", "baz"},
  1682  				false,
  1683  			},
  1684  
  1685  			// Invalid key
  1686  			{
  1687  				`${values(var.not)}`,
  1688  				nil,
  1689  				true,
  1690  			},
  1691  
  1692  			// Too many args
  1693  			{
  1694  				`${values(var.foo, "bar")}`,
  1695  				nil,
  1696  				true,
  1697  			},
  1698  
  1699  			// Not a map
  1700  			{
  1701  				`${values(var.str)}`,
  1702  				nil,
  1703  				true,
  1704  			},
  1705  
  1706  			// Map of lists
  1707  			{
  1708  				`${values(map("one", list()))}`,
  1709  				nil,
  1710  				true,
  1711  			},
  1712  		},
  1713  	})
  1714  }
  1715  
  1716  func interfaceToVariableSwallowError(input interface{}) ast.Variable {
  1717  	variable, _ := hil.InterfaceToVariable(input)
  1718  	return variable
  1719  }
  1720  
  1721  func TestInterpolateFuncElement(t *testing.T) {
  1722  	testFunction(t, testFunctionConfig{
  1723  		Vars: map[string]ast.Variable{
  1724  			"var.a_list":        interfaceToVariableSwallowError([]string{"foo", "baz"}),
  1725  			"var.a_short_list":  interfaceToVariableSwallowError([]string{"foo"}),
  1726  			"var.empty_list":    interfaceToVariableSwallowError([]interface{}{}),
  1727  			"var.a_nested_list": interfaceToVariableSwallowError([]interface{}{[]string{"foo"}, []string{"baz"}}),
  1728  		},
  1729  		Cases: []testFunctionCase{
  1730  			{
  1731  				`${element(var.a_list, "1")}`,
  1732  				"baz",
  1733  				false,
  1734  			},
  1735  
  1736  			{
  1737  				`${element(var.a_short_list, "0")}`,
  1738  				"foo",
  1739  				false,
  1740  			},
  1741  
  1742  			// Invalid index should wrap vs. out-of-bounds
  1743  			{
  1744  				`${element(var.a_list, "2")}`,
  1745  				"foo",
  1746  				false,
  1747  			},
  1748  
  1749  			// Negative number should fail
  1750  			{
  1751  				`${element(var.a_short_list, "-1")}`,
  1752  				nil,
  1753  				true,
  1754  			},
  1755  
  1756  			// Empty list should fail
  1757  			{
  1758  				`${element(var.empty_list, 0)}`,
  1759  				nil,
  1760  				true,
  1761  			},
  1762  
  1763  			// Too many args
  1764  			{
  1765  				`${element(var.a_list, "0", "2")}`,
  1766  				nil,
  1767  				true,
  1768  			},
  1769  
  1770  			// Only works on single-level lists
  1771  			{
  1772  				`${element(var.a_nested_list, "0")}`,
  1773  				nil,
  1774  				true,
  1775  			},
  1776  		},
  1777  	})
  1778  }
  1779  
  1780  func TestInterpolateFuncBase64Encode(t *testing.T) {
  1781  	testFunction(t, testFunctionConfig{
  1782  		Cases: []testFunctionCase{
  1783  			// Regular base64 encoding
  1784  			{
  1785  				`${base64encode("abc123!?$*&()'-=@~")}`,
  1786  				"YWJjMTIzIT8kKiYoKSctPUB+",
  1787  				false,
  1788  			},
  1789  		},
  1790  	})
  1791  }
  1792  
  1793  func TestInterpolateFuncBase64Decode(t *testing.T) {
  1794  	testFunction(t, testFunctionConfig{
  1795  		Cases: []testFunctionCase{
  1796  			// Regular base64 decoding
  1797  			{
  1798  				`${base64decode("YWJjMTIzIT8kKiYoKSctPUB+")}`,
  1799  				"abc123!?$*&()'-=@~",
  1800  				false,
  1801  			},
  1802  
  1803  			// Invalid base64 data decoding
  1804  			{
  1805  				`${base64decode("this-is-an-invalid-base64-data")}`,
  1806  				nil,
  1807  				true,
  1808  			},
  1809  		},
  1810  	})
  1811  }
  1812  
  1813  func TestInterpolateFuncLower(t *testing.T) {
  1814  	testFunction(t, testFunctionConfig{
  1815  		Cases: []testFunctionCase{
  1816  			{
  1817  				`${lower("HELLO")}`,
  1818  				"hello",
  1819  				false,
  1820  			},
  1821  
  1822  			{
  1823  				`${lower("")}`,
  1824  				"",
  1825  				false,
  1826  			},
  1827  
  1828  			{
  1829  				`${lower()}`,
  1830  				nil,
  1831  				true,
  1832  			},
  1833  		},
  1834  	})
  1835  }
  1836  
  1837  func TestInterpolateFuncUpper(t *testing.T) {
  1838  	testFunction(t, testFunctionConfig{
  1839  		Cases: []testFunctionCase{
  1840  			{
  1841  				`${upper("hello")}`,
  1842  				"HELLO",
  1843  				false,
  1844  			},
  1845  
  1846  			{
  1847  				`${upper("")}`,
  1848  				"",
  1849  				false,
  1850  			},
  1851  
  1852  			{
  1853  				`${upper()}`,
  1854  				nil,
  1855  				true,
  1856  			},
  1857  		},
  1858  	})
  1859  }
  1860  
  1861  func TestInterpolateFuncSha1(t *testing.T) {
  1862  	testFunction(t, testFunctionConfig{
  1863  		Cases: []testFunctionCase{
  1864  			{
  1865  				`${sha1("test")}`,
  1866  				"a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
  1867  				false,
  1868  			},
  1869  		},
  1870  	})
  1871  }
  1872  
  1873  func TestInterpolateFuncSha256(t *testing.T) {
  1874  	testFunction(t, testFunctionConfig{
  1875  		Cases: []testFunctionCase{
  1876  			{ // hexadecimal representation of sha256 sum
  1877  				`${sha256("test")}`,
  1878  				"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
  1879  				false,
  1880  			},
  1881  		},
  1882  	})
  1883  }
  1884  
  1885  func TestInterpolateFuncTitle(t *testing.T) {
  1886  	testFunction(t, testFunctionConfig{
  1887  		Cases: []testFunctionCase{
  1888  			{
  1889  				`${title("hello")}`,
  1890  				"Hello",
  1891  				false,
  1892  			},
  1893  
  1894  			{
  1895  				`${title("hello world")}`,
  1896  				"Hello World",
  1897  				false,
  1898  			},
  1899  
  1900  			{
  1901  				`${title("")}`,
  1902  				"",
  1903  				false,
  1904  			},
  1905  
  1906  			{
  1907  				`${title()}`,
  1908  				nil,
  1909  				true,
  1910  			},
  1911  		},
  1912  	})
  1913  }
  1914  
  1915  func TestInterpolateFuncTrimSpace(t *testing.T) {
  1916  	testFunction(t, testFunctionConfig{
  1917  		Cases: []testFunctionCase{
  1918  			{
  1919  				`${trimspace(" test ")}`,
  1920  				"test",
  1921  				false,
  1922  			},
  1923  		},
  1924  	})
  1925  }
  1926  
  1927  func TestInterpolateFuncBase64Sha256(t *testing.T) {
  1928  	testFunction(t, testFunctionConfig{
  1929  		Cases: []testFunctionCase{
  1930  			{
  1931  				`${base64sha256("test")}`,
  1932  				"n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=",
  1933  				false,
  1934  			},
  1935  			{ // This will differ because we're base64-encoding hex represantiation, not raw bytes
  1936  				`${base64encode(sha256("test"))}`,
  1937  				"OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZjMTViMGYwMGEwOA==",
  1938  				false,
  1939  			},
  1940  		},
  1941  	})
  1942  }
  1943  
  1944  func TestInterpolateFuncMd5(t *testing.T) {
  1945  	testFunction(t, testFunctionConfig{
  1946  		Cases: []testFunctionCase{
  1947  			{
  1948  				`${md5("tada")}`,
  1949  				"ce47d07243bb6eaf5e1322c81baf9bbf",
  1950  				false,
  1951  			},
  1952  			{ // Confirm that we're not trimming any whitespaces
  1953  				`${md5(" tada ")}`,
  1954  				"aadf191a583e53062de2d02c008141c4",
  1955  				false,
  1956  			},
  1957  			{ // We accept empty string too
  1958  				`${md5("")}`,
  1959  				"d41d8cd98f00b204e9800998ecf8427e",
  1960  				false,
  1961  			},
  1962  		},
  1963  	})
  1964  }
  1965  
  1966  func TestInterpolateFuncUUID(t *testing.T) {
  1967  	results := make(map[string]bool)
  1968  
  1969  	for i := 0; i < 100; i++ {
  1970  		ast, err := hil.Parse("${uuid()}")
  1971  		if err != nil {
  1972  			t.Fatalf("err: %s", err)
  1973  		}
  1974  
  1975  		result, err := hil.Eval(ast, langEvalConfig(nil))
  1976  		if err != nil {
  1977  			t.Fatalf("err: %s", err)
  1978  		}
  1979  
  1980  		if results[result.Value.(string)] {
  1981  			t.Fatalf("Got unexpected duplicate uuid: %s", result.Value)
  1982  		}
  1983  
  1984  		results[result.Value.(string)] = true
  1985  	}
  1986  }
  1987  
  1988  func TestInterpolateFuncTimestamp(t *testing.T) {
  1989  	currentTime := time.Now().UTC()
  1990  	ast, err := hil.Parse("${timestamp()}")
  1991  	if err != nil {
  1992  		t.Fatalf("err: %s", err)
  1993  	}
  1994  
  1995  	result, err := hil.Eval(ast, langEvalConfig(nil))
  1996  	if err != nil {
  1997  		t.Fatalf("err: %s", err)
  1998  	}
  1999  	resultTime, err := time.Parse(time.RFC3339, result.Value.(string))
  2000  	if err != nil {
  2001  		t.Fatalf("Error parsing timestamp: %s", err)
  2002  	}
  2003  
  2004  	if resultTime.Sub(currentTime).Seconds() > 10.0 {
  2005  		t.Fatalf("Timestamp Diff too large. Expected: %s\nRecieved: %s", currentTime.Format(time.RFC3339), result.Value.(string))
  2006  	}
  2007  }
  2008  
  2009  type testFunctionConfig struct {
  2010  	Cases []testFunctionCase
  2011  	Vars  map[string]ast.Variable
  2012  }
  2013  
  2014  type testFunctionCase struct {
  2015  	Input  string
  2016  	Result interface{}
  2017  	Error  bool
  2018  }
  2019  
  2020  func testFunction(t *testing.T, config testFunctionConfig) {
  2021  	for i, tc := range config.Cases {
  2022  		ast, err := hil.Parse(tc.Input)
  2023  		if err != nil {
  2024  			t.Fatalf("Case #%d: input: %#v\nerr: %v", i, tc.Input, err)
  2025  		}
  2026  
  2027  		result, err := hil.Eval(ast, langEvalConfig(config.Vars))
  2028  		if err != nil != tc.Error {
  2029  			t.Fatalf("Case #%d:\ninput: %#v\nerr: %v", i, tc.Input, err)
  2030  		}
  2031  
  2032  		if !reflect.DeepEqual(result.Value, tc.Result) {
  2033  			t.Fatalf("%d: bad output for input: %s\n\nOutput: %#v\nExpected: %#v",
  2034  				i, tc.Input, result.Value, tc.Result)
  2035  		}
  2036  	}
  2037  }
  2038  
  2039  func TestInterpolateFuncPathExpand(t *testing.T) {
  2040  	homePath, err := homedir.Dir()
  2041  	if err != nil {
  2042  		t.Fatalf("Error getting home directory: %v", err)
  2043  	}
  2044  	testFunction(t, testFunctionConfig{
  2045  		Cases: []testFunctionCase{
  2046  			{
  2047  				`${pathexpand("~/test-file")}`,
  2048  				filepath.Join(homePath, "test-file"),
  2049  				false,
  2050  			},
  2051  			{
  2052  				`${pathexpand("~/another/test/file")}`,
  2053  				filepath.Join(homePath, "another/test/file"),
  2054  				false,
  2055  			},
  2056  			{
  2057  				`${pathexpand("/root/file")}`,
  2058  				"/root/file",
  2059  				false,
  2060  			},
  2061  			{
  2062  				`${pathexpand("/")}`,
  2063  				"/",
  2064  				false,
  2065  			},
  2066  			{
  2067  				`${pathexpand()}`,
  2068  				nil,
  2069  				true,
  2070  			},
  2071  		},
  2072  	})
  2073  }