github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/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/terraform/config/lang"
    11  	"github.com/hashicorp/terraform/config/lang/ast"
    12  )
    13  
    14  func TestInterpolateFuncConcat(t *testing.T) {
    15  	testFunction(t, testFunctionConfig{
    16  		Cases: []testFunctionCase{
    17  			{
    18  				`${concat("foo", "bar")}`,
    19  				"foobar",
    20  				false,
    21  			},
    22  
    23  			{
    24  				`${concat("foo")}`,
    25  				"foo",
    26  				false,
    27  			},
    28  
    29  			{
    30  				`${concat()}`,
    31  				nil,
    32  				true,
    33  			},
    34  		},
    35  	})
    36  }
    37  
    38  func TestInterpolateFuncFile(t *testing.T) {
    39  	tf, err := ioutil.TempFile("", "tf")
    40  	if err != nil {
    41  		t.Fatalf("err: %s", err)
    42  	}
    43  	path := tf.Name()
    44  	tf.Write([]byte("foo"))
    45  	tf.Close()
    46  	defer os.Remove(path)
    47  
    48  	testFunction(t, testFunctionConfig{
    49  		Cases: []testFunctionCase{
    50  			{
    51  				fmt.Sprintf(`${file("%s")}`, path),
    52  				"foo",
    53  				false,
    54  			},
    55  
    56  			// Invalid path
    57  			{
    58  				`${file("/i/dont/exist")}`,
    59  				nil,
    60  				true,
    61  			},
    62  
    63  			// Too many args
    64  			{
    65  				`${file("foo", "bar")}`,
    66  				nil,
    67  				true,
    68  			},
    69  		},
    70  	})
    71  }
    72  
    73  func TestInterpolateFuncFormat(t *testing.T) {
    74  	testFunction(t, testFunctionConfig{
    75  		Cases: []testFunctionCase{
    76  			{
    77  				`${format("hello")}`,
    78  				"hello",
    79  				false,
    80  			},
    81  
    82  			{
    83  				`${format("hello %s", "world")}`,
    84  				"hello world",
    85  				false,
    86  			},
    87  
    88  			{
    89  				`${format("hello %d", 42)}`,
    90  				"hello 42",
    91  				false,
    92  			},
    93  
    94  			{
    95  				`${format("hello %05d", 42)}`,
    96  				"hello 00042",
    97  				false,
    98  			},
    99  
   100  			{
   101  				`${format("hello %05d", 12345)}`,
   102  				"hello 12345",
   103  				false,
   104  			},
   105  		},
   106  	})
   107  }
   108  
   109  func TestInterpolateFuncJoin(t *testing.T) {
   110  	testFunction(t, testFunctionConfig{
   111  		Cases: []testFunctionCase{
   112  			{
   113  				`${join(",")}`,
   114  				nil,
   115  				true,
   116  			},
   117  
   118  			{
   119  				`${join(",", "foo")}`,
   120  				"foo",
   121  				false,
   122  			},
   123  
   124  			/*
   125  				TODO
   126  				{
   127  					`${join(",", "foo", "bar")}`,
   128  					"foo,bar",
   129  					false,
   130  				},
   131  			*/
   132  
   133  			{
   134  				fmt.Sprintf(`${join(".", "%s")}`,
   135  					fmt.Sprintf(
   136  						"foo%sbar%sbaz",
   137  						InterpSplitDelim,
   138  						InterpSplitDelim)),
   139  				"foo.bar.baz",
   140  				false,
   141  			},
   142  		},
   143  	})
   144  }
   145  
   146  func TestInterpolateFuncReplace(t *testing.T) {
   147  	testFunction(t, testFunctionConfig{
   148  		Cases: []testFunctionCase{
   149  			// Regular search and replace
   150  			{
   151  				`${replace("hello", "hel", "bel")}`,
   152  				"bello",
   153  				false,
   154  			},
   155  
   156  			// Search string doesn't match
   157  			{
   158  				`${replace("hello", "nope", "bel")}`,
   159  				"hello",
   160  				false,
   161  			},
   162  
   163  			// Regular expression
   164  			{
   165  				`${replace("hello", "/l/", "L")}`,
   166  				"heLLo",
   167  				false,
   168  			},
   169  
   170  			{
   171  				`${replace("helo", "/(l)/", "$1$1")}`,
   172  				"hello",
   173  				false,
   174  			},
   175  
   176  			// Bad regexp
   177  			{
   178  				`${replace("helo", "/(l/", "$1$1")}`,
   179  				nil,
   180  				true,
   181  			},
   182  		},
   183  	})
   184  }
   185  
   186  func TestInterpolateFuncSplit(t *testing.T) {
   187  	testFunction(t, testFunctionConfig{
   188  		Cases: []testFunctionCase{
   189  			{
   190  				`${split(",")}`,
   191  				nil,
   192  				true,
   193  			},
   194  
   195  			{
   196  				`${split(",", "foo")}`,
   197  				"foo",
   198  				false,
   199  			},
   200  
   201  			{
   202  				`${split(".", "foo.bar.baz")}`,
   203  				fmt.Sprintf(
   204  					"foo%sbar%sbaz",
   205  					InterpSplitDelim,
   206  					InterpSplitDelim),
   207  				false,
   208  			},
   209  		},
   210  	})
   211  }
   212  
   213  func TestInterpolateFuncLookup(t *testing.T) {
   214  	testFunction(t, testFunctionConfig{
   215  		Vars: map[string]ast.Variable{
   216  			"var.foo.bar": ast.Variable{
   217  				Value: "baz",
   218  				Type:  ast.TypeString,
   219  			},
   220  		},
   221  		Cases: []testFunctionCase{
   222  			{
   223  				`${lookup("foo", "bar")}`,
   224  				"baz",
   225  				false,
   226  			},
   227  
   228  			// Invalid key
   229  			{
   230  				`${lookup("foo", "baz")}`,
   231  				nil,
   232  				true,
   233  			},
   234  
   235  			// Too many args
   236  			{
   237  				`${lookup("foo", "bar", "baz")}`,
   238  				nil,
   239  				true,
   240  			},
   241  		},
   242  	})
   243  }
   244  
   245  func TestInterpolateFuncElement(t *testing.T) {
   246  	testFunction(t, testFunctionConfig{
   247  		Cases: []testFunctionCase{
   248  			{
   249  				fmt.Sprintf(`${element("%s", "1")}`,
   250  					"foo"+InterpSplitDelim+"baz"),
   251  				"baz",
   252  				false,
   253  			},
   254  
   255  			{
   256  				`${element("foo", "0")}`,
   257  				"foo",
   258  				false,
   259  			},
   260  
   261  			// Invalid index should wrap vs. out-of-bounds
   262  			{
   263  				fmt.Sprintf(`${element("%s", "2")}`,
   264  					"foo"+InterpSplitDelim+"baz"),
   265  				"foo",
   266  				false,
   267  			},
   268  
   269  			// Too many args
   270  			{
   271  				fmt.Sprintf(`${element("%s", "0", "2")}`,
   272  					"foo"+InterpSplitDelim+"baz"),
   273  				nil,
   274  				true,
   275  			},
   276  		},
   277  	})
   278  }
   279  
   280  type testFunctionConfig struct {
   281  	Cases []testFunctionCase
   282  	Vars  map[string]ast.Variable
   283  }
   284  
   285  type testFunctionCase struct {
   286  	Input  string
   287  	Result interface{}
   288  	Error  bool
   289  }
   290  
   291  func testFunction(t *testing.T, config testFunctionConfig) {
   292  	for i, tc := range config.Cases {
   293  		ast, err := lang.Parse(tc.Input)
   294  		if err != nil {
   295  			t.Fatalf("%d: err: %s", i, err)
   296  		}
   297  
   298  		out, _, err := lang.Eval(ast, langEvalConfig(config.Vars))
   299  		if (err != nil) != tc.Error {
   300  			t.Fatalf("%d: err: %s", i, err)
   301  		}
   302  
   303  		if !reflect.DeepEqual(out, tc.Result) {
   304  			t.Fatalf(
   305  				"%d: bad output for input: %s\n\nOutput: %#v",
   306  				i, tc.Input, out)
   307  		}
   308  	}
   309  }