github.com/miquella/terraform@v0.6.17-0.20160517195040-40db82f25ec0/config/interpolate_funcs_test.go (about)

     1  package config
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"reflect"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/hil"
    11  	"github.com/hashicorp/hil/ast"
    12  )
    13  
    14  func TestInterpolateFuncCompact(t *testing.T) {
    15  	testFunction(t, testFunctionConfig{
    16  		Cases: []testFunctionCase{
    17  			// empty string within array
    18  			{
    19  				`${compact(split(",", "a,,b"))}`,
    20  				[]interface{}{"a", "b"},
    21  				false,
    22  			},
    23  
    24  			// empty string at the end of array
    25  			{
    26  				`${compact(split(",", "a,b,"))}`,
    27  				[]interface{}{"a", "b"},
    28  				false,
    29  			},
    30  
    31  			// single empty string
    32  			{
    33  				`${compact(split(",", ""))}`,
    34  				[]interface{}{},
    35  				false,
    36  			},
    37  		},
    38  	})
    39  }
    40  
    41  func TestInterpolateFuncCidrHost(t *testing.T) {
    42  	testFunction(t, testFunctionConfig{
    43  		Cases: []testFunctionCase{
    44  			{
    45  				`${cidrhost("192.168.1.0/24", 5)}`,
    46  				"192.168.1.5",
    47  				false,
    48  			},
    49  			{
    50  				`${cidrhost("192.168.1.0/30", 255)}`,
    51  				nil,
    52  				true, // 255 doesn't fit in two bits
    53  			},
    54  			{
    55  				`${cidrhost("not-a-cidr", 6)}`,
    56  				nil,
    57  				true, // not a valid CIDR mask
    58  			},
    59  			{
    60  				`${cidrhost("10.256.0.0/8", 6)}`,
    61  				nil,
    62  				true, // can't have an octet >255
    63  			},
    64  		},
    65  	})
    66  }
    67  
    68  func TestInterpolateFuncCidrNetmask(t *testing.T) {
    69  	testFunction(t, testFunctionConfig{
    70  		Cases: []testFunctionCase{
    71  			{
    72  				`${cidrnetmask("192.168.1.0/24")}`,
    73  				"255.255.255.0",
    74  				false,
    75  			},
    76  			{
    77  				`${cidrnetmask("192.168.1.0/32")}`,
    78  				"255.255.255.255",
    79  				false,
    80  			},
    81  			{
    82  				`${cidrnetmask("0.0.0.0/0")}`,
    83  				"0.0.0.0",
    84  				false,
    85  			},
    86  			{
    87  				// This doesn't really make sense for IPv6 networks
    88  				// but it ought to do something sensible anyway.
    89  				`${cidrnetmask("1::/64")}`,
    90  				"ffff:ffff:ffff:ffff::",
    91  				false,
    92  			},
    93  			{
    94  				`${cidrnetmask("not-a-cidr")}`,
    95  				nil,
    96  				true, // not a valid CIDR mask
    97  			},
    98  			{
    99  				`${cidrnetmask("10.256.0.0/8")}`,
   100  				nil,
   101  				true, // can't have an octet >255
   102  			},
   103  		},
   104  	})
   105  }
   106  
   107  func TestInterpolateFuncCidrSubnet(t *testing.T) {
   108  	testFunction(t, testFunctionConfig{
   109  		Cases: []testFunctionCase{
   110  			{
   111  				`${cidrsubnet("192.168.2.0/20", 4, 6)}`,
   112  				"192.168.6.0/24",
   113  				false,
   114  			},
   115  			{
   116  				`${cidrsubnet("fe80::/48", 16, 6)}`,
   117  				"fe80:0:0:6::/64",
   118  				false,
   119  			},
   120  			{
   121  				// IPv4 address encoded in IPv6 syntax gets normalized
   122  				`${cidrsubnet("::ffff:192.168.0.0/112", 8, 6)}`,
   123  				"192.168.6.0/24",
   124  				false,
   125  			},
   126  			{
   127  				`${cidrsubnet("192.168.0.0/30", 4, 6)}`,
   128  				nil,
   129  				true, // not enough bits left
   130  			},
   131  			{
   132  				`${cidrsubnet("192.168.0.0/16", 2, 16)}`,
   133  				nil,
   134  				true, // can't encode 16 in 2 bits
   135  			},
   136  			{
   137  				`${cidrsubnet("not-a-cidr", 4, 6)}`,
   138  				nil,
   139  				true, // not a valid CIDR mask
   140  			},
   141  			{
   142  				`${cidrsubnet("10.256.0.0/8", 4, 6)}`,
   143  				nil,
   144  				true, // can't have an octet >255
   145  			},
   146  		},
   147  	})
   148  }
   149  
   150  func TestInterpolateFuncCoalesce(t *testing.T) {
   151  	testFunction(t, testFunctionConfig{
   152  		Cases: []testFunctionCase{
   153  			{
   154  				`${coalesce("first", "second", "third")}`,
   155  				"first",
   156  				false,
   157  			},
   158  			{
   159  				`${coalesce("", "second", "third")}`,
   160  				"second",
   161  				false,
   162  			},
   163  			{
   164  				`${coalesce("", "", "")}`,
   165  				"",
   166  				false,
   167  			},
   168  			{
   169  				`${coalesce("foo")}`,
   170  				nil,
   171  				true,
   172  			},
   173  		},
   174  	})
   175  }
   176  
   177  func TestInterpolateFuncConcat(t *testing.T) {
   178  	testFunction(t, testFunctionConfig{
   179  		Cases: []testFunctionCase{
   180  			// String + list
   181  			{
   182  				`${concat("a", split(",", "b,c"))}`,
   183  				[]interface{}{"a", "b", "c"},
   184  				false,
   185  			},
   186  
   187  			// List + string
   188  			{
   189  				`${concat(split(",", "a,b"), "c")}`,
   190  				[]interface{}{"a", "b", "c"},
   191  				false,
   192  			},
   193  
   194  			// Single list
   195  			{
   196  				`${concat(split(",", ",foo,"))}`,
   197  				[]interface{}{"", "foo", ""},
   198  				false,
   199  			},
   200  			{
   201  				`${concat(split(",", "a,b,c"))}`,
   202  				[]interface{}{"a", "b", "c"},
   203  				false,
   204  			},
   205  
   206  			// Two lists
   207  			{
   208  				`${concat(split(",", "a,b,c"), split(",", "d,e"))}`,
   209  				[]interface{}{"a", "b", "c", "d", "e"},
   210  				false,
   211  			},
   212  			// Two lists with different separators
   213  			{
   214  				`${concat(split(",", "a,b,c"), split(" ", "d e"))}`,
   215  				[]interface{}{"a", "b", "c", "d", "e"},
   216  				false,
   217  			},
   218  
   219  			// More lists
   220  			{
   221  				`${concat(split(",", "a,b"), split(",", "c,d"), split(",", "e,f"), split(",", "0,1"))}`,
   222  				[]interface{}{"a", "b", "c", "d", "e", "f", "0", "1"},
   223  				false,
   224  			},
   225  		},
   226  	})
   227  }
   228  
   229  func TestInterpolateFuncFile(t *testing.T) {
   230  	tf, err := ioutil.TempFile("", "tf")
   231  	if err != nil {
   232  		t.Fatalf("err: %s", err)
   233  	}
   234  	path := tf.Name()
   235  	tf.Write([]byte("foo"))
   236  	tf.Close()
   237  	defer os.Remove(path)
   238  
   239  	testFunction(t, testFunctionConfig{
   240  		Cases: []testFunctionCase{
   241  			{
   242  				fmt.Sprintf(`${file("%s")}`, path),
   243  				"foo",
   244  				false,
   245  			},
   246  
   247  			// Invalid path
   248  			{
   249  				`${file("/i/dont/exist")}`,
   250  				nil,
   251  				true,
   252  			},
   253  
   254  			// Too many args
   255  			{
   256  				`${file("foo", "bar")}`,
   257  				nil,
   258  				true,
   259  			},
   260  		},
   261  	})
   262  }
   263  
   264  func TestInterpolateFuncFormat(t *testing.T) {
   265  	testFunction(t, testFunctionConfig{
   266  		Cases: []testFunctionCase{
   267  			{
   268  				`${format("hello")}`,
   269  				"hello",
   270  				false,
   271  			},
   272  
   273  			{
   274  				`${format("hello %s", "world")}`,
   275  				"hello world",
   276  				false,
   277  			},
   278  
   279  			{
   280  				`${format("hello %d", 42)}`,
   281  				"hello 42",
   282  				false,
   283  			},
   284  
   285  			{
   286  				`${format("hello %05d", 42)}`,
   287  				"hello 00042",
   288  				false,
   289  			},
   290  
   291  			{
   292  				`${format("hello %05d", 12345)}`,
   293  				"hello 12345",
   294  				false,
   295  			},
   296  		},
   297  	})
   298  }
   299  
   300  func TestInterpolateFuncFormatList(t *testing.T) {
   301  	testFunction(t, testFunctionConfig{
   302  		Cases: []testFunctionCase{
   303  			// formatlist requires at least one list
   304  			{
   305  				`${formatlist("hello")}`,
   306  				nil,
   307  				true,
   308  			},
   309  			{
   310  				`${formatlist("hello %s", "world")}`,
   311  				nil,
   312  				true,
   313  			},
   314  			// formatlist applies to each list element in turn
   315  			{
   316  				`${formatlist("<%s>", split(",", "A,B"))}`,
   317  				[]interface{}{"<A>", "<B>"},
   318  				false,
   319  			},
   320  			// formatlist repeats scalar elements
   321  			{
   322  				`${join(", ", formatlist("%s=%s", "x", split(",", "A,B,C")))}`,
   323  				"x=A, x=B, x=C",
   324  				false,
   325  			},
   326  			// Multiple lists are walked in parallel
   327  			{
   328  				`${join(", ", formatlist("%s=%s", split(",", "A,B,C"), split(",", "1,2,3")))}`,
   329  				"A=1, B=2, C=3",
   330  				false,
   331  			},
   332  			// Mismatched list lengths generate an error
   333  			{
   334  				`${formatlist("%s=%2s", split(",", "A,B,C,D"), split(",", "1,2,3"))}`,
   335  				nil,
   336  				true,
   337  			},
   338  			// Works with lists of length 1 [GH-2240]
   339  			{
   340  				`${formatlist("%s.id", split(",", "demo-rest-elb"))}`,
   341  				[]interface{}{"demo-rest-elb.id"},
   342  				false,
   343  			},
   344  		},
   345  	})
   346  }
   347  
   348  func TestInterpolateFuncIndex(t *testing.T) {
   349  	testFunction(t, testFunctionConfig{
   350  		Vars: map[string]ast.Variable{
   351  			"var.list1": interfaceToVariableSwallowError([]string{"notfoo", "stillnotfoo", "bar"}),
   352  			"var.list2": interfaceToVariableSwallowError([]string{"foo"}),
   353  			"var.list3": interfaceToVariableSwallowError([]string{"foo", "spam", "bar", "eggs"}),
   354  		},
   355  		Cases: []testFunctionCase{
   356  			{
   357  				`${index("test", "")}`,
   358  				nil,
   359  				true,
   360  			},
   361  
   362  			{
   363  				`${index(var.list1, "foo")}`,
   364  				nil,
   365  				true,
   366  			},
   367  
   368  			{
   369  				`${index(var.list2, "foo")}`,
   370  				"0",
   371  				false,
   372  			},
   373  
   374  			{
   375  				`${index(var.list3, "bar")}`,
   376  				"2",
   377  				false,
   378  			},
   379  		},
   380  	})
   381  }
   382  
   383  func TestInterpolateFuncJoin(t *testing.T) {
   384  	testFunction(t, testFunctionConfig{
   385  		Vars: map[string]ast.Variable{
   386  			"var.a_list":        interfaceToVariableSwallowError([]string{"foo"}),
   387  			"var.a_longer_list": interfaceToVariableSwallowError([]string{"foo", "bar", "baz"}),
   388  		},
   389  		Cases: []testFunctionCase{
   390  			{
   391  				`${join(",")}`,
   392  				nil,
   393  				true,
   394  			},
   395  
   396  			{
   397  				`${join(",", var.a_list)}`,
   398  				"foo",
   399  				false,
   400  			},
   401  
   402  			{
   403  				`${join(".", var.a_longer_list)}`,
   404  				"foo.bar.baz",
   405  				false,
   406  			},
   407  		},
   408  	})
   409  }
   410  
   411  func TestInterpolateFuncJSONEncode(t *testing.T) {
   412  	testFunction(t, testFunctionConfig{
   413  		Vars: map[string]ast.Variable{
   414  			"easy": ast.Variable{
   415  				Value: "test",
   416  				Type:  ast.TypeString,
   417  			},
   418  			"hard": ast.Variable{
   419  				Value: " foo \\ \n \t \" bar ",
   420  				Type:  ast.TypeString,
   421  			},
   422  		},
   423  		Cases: []testFunctionCase{
   424  			{
   425  				`${jsonencode("test")}`,
   426  				`"test"`,
   427  				false,
   428  			},
   429  			{
   430  				`${jsonencode(easy)}`,
   431  				`"test"`,
   432  				false,
   433  			},
   434  			{
   435  				`${jsonencode(hard)}`,
   436  				`" foo \\ \n \t \" bar "`,
   437  				false,
   438  			},
   439  			{
   440  				`${jsonencode("")}`,
   441  				`""`,
   442  				false,
   443  			},
   444  			{
   445  				`${jsonencode()}`,
   446  				nil,
   447  				true,
   448  			},
   449  		},
   450  	})
   451  }
   452  
   453  func TestInterpolateFuncReplace(t *testing.T) {
   454  	testFunction(t, testFunctionConfig{
   455  		Cases: []testFunctionCase{
   456  			// Regular search and replace
   457  			{
   458  				`${replace("hello", "hel", "bel")}`,
   459  				"bello",
   460  				false,
   461  			},
   462  
   463  			// Search string doesn't match
   464  			{
   465  				`${replace("hello", "nope", "bel")}`,
   466  				"hello",
   467  				false,
   468  			},
   469  
   470  			// Regular expression
   471  			{
   472  				`${replace("hello", "/l/", "L")}`,
   473  				"heLLo",
   474  				false,
   475  			},
   476  
   477  			{
   478  				`${replace("helo", "/(l)/", "$1$1")}`,
   479  				"hello",
   480  				false,
   481  			},
   482  
   483  			// Bad regexp
   484  			{
   485  				`${replace("helo", "/(l/", "$1$1")}`,
   486  				nil,
   487  				true,
   488  			},
   489  		},
   490  	})
   491  }
   492  
   493  func TestInterpolateFuncLength(t *testing.T) {
   494  	testFunction(t, testFunctionConfig{
   495  		Cases: []testFunctionCase{
   496  			// Raw strings
   497  			{
   498  				`${length("")}`,
   499  				"0",
   500  				false,
   501  			},
   502  			{
   503  				`${length("a")}`,
   504  				"1",
   505  				false,
   506  			},
   507  			{
   508  				`${length(" ")}`,
   509  				"1",
   510  				false,
   511  			},
   512  			{
   513  				`${length(" a ,")}`,
   514  				"4",
   515  				false,
   516  			},
   517  			{
   518  				`${length("aaa")}`,
   519  				"3",
   520  				false,
   521  			},
   522  
   523  			// Lists
   524  			{
   525  				`${length(split(",", "a"))}`,
   526  				"1",
   527  				false,
   528  			},
   529  			{
   530  				`${length(split(",", "foo,"))}`,
   531  				"2",
   532  				false,
   533  			},
   534  			{
   535  				`${length(split(",", ",foo,"))}`,
   536  				"3",
   537  				false,
   538  			},
   539  			{
   540  				`${length(split(",", "foo,bar"))}`,
   541  				"2",
   542  				false,
   543  			},
   544  			{
   545  				`${length(split(".", "one.two.three.four.five"))}`,
   546  				"5",
   547  				false,
   548  			},
   549  			// Want length 0 if we split an empty string then compact
   550  			{
   551  				`${length(compact(split(",", "")))}`,
   552  				"0",
   553  				false,
   554  			},
   555  		},
   556  	})
   557  }
   558  
   559  func TestInterpolateFuncSignum(t *testing.T) {
   560  	testFunction(t, testFunctionConfig{
   561  		Cases: []testFunctionCase{
   562  			{
   563  				`${signum()}`,
   564  				nil,
   565  				true,
   566  			},
   567  
   568  			{
   569  				`${signum("")}`,
   570  				nil,
   571  				true,
   572  			},
   573  
   574  			{
   575  				`${signum(0)}`,
   576  				"0",
   577  				false,
   578  			},
   579  
   580  			{
   581  				`${signum(15)}`,
   582  				"1",
   583  				false,
   584  			},
   585  
   586  			{
   587  				`${signum(-29)}`,
   588  				"-1",
   589  				false,
   590  			},
   591  		},
   592  	})
   593  }
   594  
   595  func TestInterpolateFuncSplit(t *testing.T) {
   596  	testFunction(t, testFunctionConfig{
   597  		Cases: []testFunctionCase{
   598  			{
   599  				`${split(",")}`,
   600  				nil,
   601  				true,
   602  			},
   603  
   604  			{
   605  				`${split(",", "")}`,
   606  				[]interface{}{""},
   607  				false,
   608  			},
   609  
   610  			{
   611  				`${split(",", "foo")}`,
   612  				[]interface{}{"foo"},
   613  				false,
   614  			},
   615  
   616  			{
   617  				`${split(",", ",,,")}`,
   618  				[]interface{}{"", "", "", ""},
   619  				false,
   620  			},
   621  
   622  			{
   623  				`${split(",", "foo,")}`,
   624  				[]interface{}{"foo", ""},
   625  				false,
   626  			},
   627  
   628  			{
   629  				`${split(",", ",foo,")}`,
   630  				[]interface{}{"", "foo", ""},
   631  				false,
   632  			},
   633  
   634  			{
   635  				`${split(".", "foo.bar.baz")}`,
   636  				[]interface{}{"foo", "bar", "baz"},
   637  				false,
   638  			},
   639  		},
   640  	})
   641  }
   642  
   643  func TestInterpolateFuncLookup(t *testing.T) {
   644  	testFunction(t, testFunctionConfig{
   645  		Vars: map[string]ast.Variable{
   646  			"var.foo": ast.Variable{
   647  				Type: ast.TypeMap,
   648  				Value: map[string]ast.Variable{
   649  					"bar": ast.Variable{
   650  						Type:  ast.TypeString,
   651  						Value: "baz",
   652  					},
   653  				},
   654  			},
   655  		},
   656  		Cases: []testFunctionCase{
   657  			{
   658  				`${lookup(var.foo, "bar")}`,
   659  				"baz",
   660  				false,
   661  			},
   662  
   663  			// Invalid key
   664  			{
   665  				`${lookup(var.foo, "baz")}`,
   666  				nil,
   667  				true,
   668  			},
   669  
   670  			// Too many args
   671  			{
   672  				`${lookup(var.foo, "bar", "baz")}`,
   673  				nil,
   674  				true,
   675  			},
   676  		},
   677  	})
   678  }
   679  
   680  func TestInterpolateFuncKeys(t *testing.T) {
   681  	testFunction(t, testFunctionConfig{
   682  		Vars: map[string]ast.Variable{
   683  			"var.foo": ast.Variable{
   684  				Type: ast.TypeMap,
   685  				Value: map[string]ast.Variable{
   686  					"bar": ast.Variable{
   687  						Value: "baz",
   688  						Type:  ast.TypeString,
   689  					},
   690  					"qux": ast.Variable{
   691  						Value: "quack",
   692  						Type:  ast.TypeString,
   693  					},
   694  				},
   695  			},
   696  			"var.str": ast.Variable{
   697  				Value: "astring",
   698  				Type:  ast.TypeString,
   699  			},
   700  		},
   701  		Cases: []testFunctionCase{
   702  			{
   703  				`${keys(var.foo)}`,
   704  				[]interface{}{"bar", "qux"},
   705  				false,
   706  			},
   707  
   708  			// Invalid key
   709  			{
   710  				`${keys(var.not)}`,
   711  				nil,
   712  				true,
   713  			},
   714  
   715  			// Too many args
   716  			{
   717  				`${keys(var.foo, "bar")}`,
   718  				nil,
   719  				true,
   720  			},
   721  
   722  			// Not a map
   723  			{
   724  				`${keys(var.str)}`,
   725  				nil,
   726  				true,
   727  			},
   728  		},
   729  	})
   730  }
   731  
   732  func TestInterpolateFuncValues(t *testing.T) {
   733  	testFunction(t, testFunctionConfig{
   734  		Vars: map[string]ast.Variable{
   735  			"var.foo": ast.Variable{
   736  				Type: ast.TypeMap,
   737  				Value: map[string]ast.Variable{
   738  					"bar": ast.Variable{
   739  						Value: "quack",
   740  						Type:  ast.TypeString,
   741  					},
   742  					"qux": ast.Variable{
   743  						Value: "baz",
   744  						Type:  ast.TypeString,
   745  					},
   746  				},
   747  			},
   748  			"var.str": ast.Variable{
   749  				Value: "astring",
   750  				Type:  ast.TypeString,
   751  			},
   752  		},
   753  		Cases: []testFunctionCase{
   754  			{
   755  				`${values(var.foo)}`,
   756  				[]interface{}{"quack", "baz"},
   757  				false,
   758  			},
   759  
   760  			// Invalid key
   761  			{
   762  				`${values(var.not)}`,
   763  				nil,
   764  				true,
   765  			},
   766  
   767  			// Too many args
   768  			{
   769  				`${values(var.foo, "bar")}`,
   770  				nil,
   771  				true,
   772  			},
   773  
   774  			// Not a map
   775  			{
   776  				`${values(var.str)}`,
   777  				nil,
   778  				true,
   779  			},
   780  		},
   781  	})
   782  }
   783  
   784  func interfaceToVariableSwallowError(input interface{}) ast.Variable {
   785  	variable, _ := hil.InterfaceToVariable(input)
   786  	return variable
   787  }
   788  
   789  func TestInterpolateFuncElement(t *testing.T) {
   790  	testFunction(t, testFunctionConfig{
   791  		Vars: map[string]ast.Variable{
   792  			"var.a_list":       interfaceToVariableSwallowError([]string{"foo", "baz"}),
   793  			"var.a_short_list": interfaceToVariableSwallowError([]string{"foo"}),
   794  		},
   795  		Cases: []testFunctionCase{
   796  			{
   797  				`${element(var.a_list, "1")}`,
   798  				"baz",
   799  				false,
   800  			},
   801  
   802  			{
   803  				`${element(var.a_short_list, "0")}`,
   804  				"foo",
   805  				false,
   806  			},
   807  
   808  			// Invalid index should wrap vs. out-of-bounds
   809  			{
   810  				`${element(var.a_list, "2")}`,
   811  				"foo",
   812  				false,
   813  			},
   814  
   815  			// Negative number should fail
   816  			{
   817  				`${element(var.a_short_list, "-1")}`,
   818  				nil,
   819  				true,
   820  			},
   821  
   822  			// Too many args
   823  			{
   824  				`${element(var.a_list, "0", "2")}`,
   825  				nil,
   826  				true,
   827  			},
   828  		},
   829  	})
   830  }
   831  
   832  func TestInterpolateFuncBase64Encode(t *testing.T) {
   833  	testFunction(t, testFunctionConfig{
   834  		Cases: []testFunctionCase{
   835  			// Regular base64 encoding
   836  			{
   837  				`${base64encode("abc123!?$*&()'-=@~")}`,
   838  				"YWJjMTIzIT8kKiYoKSctPUB+",
   839  				false,
   840  			},
   841  		},
   842  	})
   843  }
   844  
   845  func TestInterpolateFuncBase64Decode(t *testing.T) {
   846  	testFunction(t, testFunctionConfig{
   847  		Cases: []testFunctionCase{
   848  			// Regular base64 decoding
   849  			{
   850  				`${base64decode("YWJjMTIzIT8kKiYoKSctPUB+")}`,
   851  				"abc123!?$*&()'-=@~",
   852  				false,
   853  			},
   854  
   855  			// Invalid base64 data decoding
   856  			{
   857  				`${base64decode("this-is-an-invalid-base64-data")}`,
   858  				nil,
   859  				true,
   860  			},
   861  		},
   862  	})
   863  }
   864  
   865  func TestInterpolateFuncLower(t *testing.T) {
   866  	testFunction(t, testFunctionConfig{
   867  		Cases: []testFunctionCase{
   868  			{
   869  				`${lower("HELLO")}`,
   870  				"hello",
   871  				false,
   872  			},
   873  
   874  			{
   875  				`${lower("")}`,
   876  				"",
   877  				false,
   878  			},
   879  
   880  			{
   881  				`${lower()}`,
   882  				nil,
   883  				true,
   884  			},
   885  		},
   886  	})
   887  }
   888  
   889  func TestInterpolateFuncUpper(t *testing.T) {
   890  	testFunction(t, testFunctionConfig{
   891  		Cases: []testFunctionCase{
   892  			{
   893  				`${upper("hello")}`,
   894  				"HELLO",
   895  				false,
   896  			},
   897  
   898  			{
   899  				`${upper("")}`,
   900  				"",
   901  				false,
   902  			},
   903  
   904  			{
   905  				`${upper()}`,
   906  				nil,
   907  				true,
   908  			},
   909  		},
   910  	})
   911  }
   912  
   913  func TestInterpolateFuncSha1(t *testing.T) {
   914  	testFunction(t, testFunctionConfig{
   915  		Cases: []testFunctionCase{
   916  			{
   917  				`${sha1("test")}`,
   918  				"a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
   919  				false,
   920  			},
   921  		},
   922  	})
   923  }
   924  
   925  func TestInterpolateFuncSha256(t *testing.T) {
   926  	testFunction(t, testFunctionConfig{
   927  		Cases: []testFunctionCase{
   928  			{ // hexadecimal representation of sha256 sum
   929  				`${sha256("test")}`,
   930  				"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
   931  				false,
   932  			},
   933  		},
   934  	})
   935  }
   936  
   937  func TestInterpolateFuncTrimSpace(t *testing.T) {
   938  	testFunction(t, testFunctionConfig{
   939  		Cases: []testFunctionCase{
   940  			{
   941  				`${trimspace(" test ")}`,
   942  				"test",
   943  				false,
   944  			},
   945  		},
   946  	})
   947  }
   948  
   949  func TestInterpolateFuncBase64Sha256(t *testing.T) {
   950  	testFunction(t, testFunctionConfig{
   951  		Cases: []testFunctionCase{
   952  			{
   953  				`${base64sha256("test")}`,
   954  				"n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=",
   955  				false,
   956  			},
   957  			{ // This will differ because we're base64-encoding hex represantiation, not raw bytes
   958  				`${base64encode(sha256("test"))}`,
   959  				"OWY4NmQwODE4ODRjN2Q2NTlhMmZlYWEwYzU1YWQwMTVhM2JmNGYxYjJiMGI4MjJjZDE1ZDZjMTViMGYwMGEwOA==",
   960  				false,
   961  			},
   962  		},
   963  	})
   964  }
   965  
   966  func TestInterpolateFuncMd5(t *testing.T) {
   967  	testFunction(t, testFunctionConfig{
   968  		Cases: []testFunctionCase{
   969  			{
   970  				`${md5("tada")}`,
   971  				"ce47d07243bb6eaf5e1322c81baf9bbf",
   972  				false,
   973  			},
   974  			{ // Confirm that we're not trimming any whitespaces
   975  				`${md5(" tada ")}`,
   976  				"aadf191a583e53062de2d02c008141c4",
   977  				false,
   978  			},
   979  			{ // We accept empty string too
   980  				`${md5("")}`,
   981  				"d41d8cd98f00b204e9800998ecf8427e",
   982  				false,
   983  			},
   984  		},
   985  	})
   986  }
   987  
   988  func TestInterpolateFuncUUID(t *testing.T) {
   989  	results := make(map[string]bool)
   990  
   991  	for i := 0; i < 100; i++ {
   992  		ast, err := hil.Parse("${uuid()}")
   993  		if err != nil {
   994  			t.Fatalf("err: %s", err)
   995  		}
   996  
   997  		result, err := hil.Eval(ast, langEvalConfig(nil))
   998  		if err != nil {
   999  			t.Fatalf("err: %s", err)
  1000  		}
  1001  
  1002  		if results[result.Value.(string)] {
  1003  			t.Fatalf("Got unexpected duplicate uuid: %s", result.Value)
  1004  		}
  1005  
  1006  		results[result.Value.(string)] = true
  1007  	}
  1008  }
  1009  
  1010  type testFunctionConfig struct {
  1011  	Cases []testFunctionCase
  1012  	Vars  map[string]ast.Variable
  1013  }
  1014  
  1015  type testFunctionCase struct {
  1016  	Input  string
  1017  	Result interface{}
  1018  	Error  bool
  1019  }
  1020  
  1021  func testFunction(t *testing.T, config testFunctionConfig) {
  1022  	for i, tc := range config.Cases {
  1023  		ast, err := hil.Parse(tc.Input)
  1024  		if err != nil {
  1025  			t.Fatalf("Case #%d: input: %#v\nerr: %s", i, tc.Input, err)
  1026  		}
  1027  
  1028  		result, err := hil.Eval(ast, langEvalConfig(config.Vars))
  1029  		if err != nil != tc.Error {
  1030  			t.Fatalf("Case #%d:\ninput: %#v\nerr: %s", i, tc.Input, err)
  1031  		}
  1032  
  1033  		if !reflect.DeepEqual(result.Value, tc.Result) {
  1034  			t.Fatalf("%d: bad output for input: %s\n\nOutput: %#v\nExpected: %#v",
  1035  				i, tc.Input, result.Value, tc.Result)
  1036  		}
  1037  	}
  1038  }