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