github.com/hobbeswalsh/terraform@v0.3.7-0.20150619183303-ad17cf55a0fa/config/lang/check_types_test.go (about)

     1  package lang
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/hashicorp/terraform/config/lang/ast"
     7  )
     8  
     9  func TestTypeCheck(t *testing.T) {
    10  	cases := []struct {
    11  		Input string
    12  		Scope ast.Scope
    13  		Error bool
    14  	}{
    15  		{
    16  			"foo",
    17  			&ast.BasicScope{},
    18  			false,
    19  		},
    20  
    21  		{
    22  			"foo ${bar}",
    23  			&ast.BasicScope{
    24  				VarMap: map[string]ast.Variable{
    25  					"bar": ast.Variable{
    26  						Value: "baz",
    27  						Type:  ast.TypeString,
    28  					},
    29  				},
    30  			},
    31  			false,
    32  		},
    33  
    34  		{
    35  			"foo ${rand()}",
    36  			&ast.BasicScope{
    37  				FuncMap: map[string]ast.Function{
    38  					"rand": ast.Function{
    39  						ReturnType: ast.TypeString,
    40  						Callback: func([]interface{}) (interface{}, error) {
    41  							return "42", nil
    42  						},
    43  					},
    44  				},
    45  			},
    46  			false,
    47  		},
    48  
    49  		{
    50  			`foo ${rand("42")}`,
    51  			&ast.BasicScope{
    52  				FuncMap: map[string]ast.Function{
    53  					"rand": ast.Function{
    54  						ArgTypes:   []ast.Type{ast.TypeString},
    55  						ReturnType: ast.TypeString,
    56  						Callback: func([]interface{}) (interface{}, error) {
    57  							return "42", nil
    58  						},
    59  					},
    60  				},
    61  			},
    62  			false,
    63  		},
    64  
    65  		{
    66  			`foo ${rand(42)}`,
    67  			&ast.BasicScope{
    68  				FuncMap: map[string]ast.Function{
    69  					"rand": ast.Function{
    70  						ArgTypes:   []ast.Type{ast.TypeString},
    71  						ReturnType: ast.TypeString,
    72  						Callback: func([]interface{}) (interface{}, error) {
    73  							return "42", nil
    74  						},
    75  					},
    76  				},
    77  			},
    78  			true,
    79  		},
    80  
    81  		{
    82  			`foo ${rand()}`,
    83  			&ast.BasicScope{
    84  				FuncMap: map[string]ast.Function{
    85  					"rand": ast.Function{
    86  						ArgTypes:     nil,
    87  						ReturnType:   ast.TypeString,
    88  						Variadic:     true,
    89  						VariadicType: ast.TypeString,
    90  						Callback: func([]interface{}) (interface{}, error) {
    91  							return "42", nil
    92  						},
    93  					},
    94  				},
    95  			},
    96  			false,
    97  		},
    98  
    99  		{
   100  			`foo ${rand("42")}`,
   101  			&ast.BasicScope{
   102  				FuncMap: map[string]ast.Function{
   103  					"rand": ast.Function{
   104  						ArgTypes:     nil,
   105  						ReturnType:   ast.TypeString,
   106  						Variadic:     true,
   107  						VariadicType: ast.TypeString,
   108  						Callback: func([]interface{}) (interface{}, error) {
   109  							return "42", nil
   110  						},
   111  					},
   112  				},
   113  			},
   114  			false,
   115  		},
   116  
   117  		{
   118  			`foo ${rand("42", 42)}`,
   119  			&ast.BasicScope{
   120  				FuncMap: map[string]ast.Function{
   121  					"rand": ast.Function{
   122  						ArgTypes:     nil,
   123  						ReturnType:   ast.TypeString,
   124  						Variadic:     true,
   125  						VariadicType: ast.TypeString,
   126  						Callback: func([]interface{}) (interface{}, error) {
   127  							return "42", nil
   128  						},
   129  					},
   130  				},
   131  			},
   132  			true,
   133  		},
   134  
   135  		{
   136  			"foo ${bar}",
   137  			&ast.BasicScope{
   138  				VarMap: map[string]ast.Variable{
   139  					"bar": ast.Variable{
   140  						Value: 42,
   141  						Type:  ast.TypeInt,
   142  					},
   143  				},
   144  			},
   145  			true,
   146  		},
   147  
   148  		{
   149  			"foo ${rand()}",
   150  			&ast.BasicScope{
   151  				FuncMap: map[string]ast.Function{
   152  					"rand": ast.Function{
   153  						ReturnType: ast.TypeInt,
   154  						Callback: func([]interface{}) (interface{}, error) {
   155  							return 42, nil
   156  						},
   157  					},
   158  				},
   159  			},
   160  			true,
   161  		},
   162  	}
   163  
   164  	for _, tc := range cases {
   165  		node, err := Parse(tc.Input)
   166  		if err != nil {
   167  			t.Fatalf("Error: %s\n\nInput: %s", err, tc.Input)
   168  		}
   169  
   170  		visitor := &TypeCheck{Scope: tc.Scope}
   171  		err = visitor.Visit(node)
   172  		if (err != nil) != tc.Error {
   173  			t.Fatalf("Error: %s\n\nInput: %s", err, tc.Input)
   174  		}
   175  	}
   176  }
   177  
   178  func TestTypeCheck_implicit(t *testing.T) {
   179  	implicitMap := map[ast.Type]map[ast.Type]string{
   180  		ast.TypeInt: {
   181  			ast.TypeString: "intToString",
   182  		},
   183  	}
   184  
   185  	cases := []struct {
   186  		Input string
   187  		Scope *ast.BasicScope
   188  		Error bool
   189  	}{
   190  		{
   191  			"foo ${bar}",
   192  			&ast.BasicScope{
   193  				VarMap: map[string]ast.Variable{
   194  					"bar": ast.Variable{
   195  						Value: 42,
   196  						Type:  ast.TypeInt,
   197  					},
   198  				},
   199  			},
   200  			false,
   201  		},
   202  
   203  		{
   204  			"foo ${foo(42)}",
   205  			&ast.BasicScope{
   206  				FuncMap: map[string]ast.Function{
   207  					"foo": ast.Function{
   208  						ArgTypes:   []ast.Type{ast.TypeString},
   209  						ReturnType: ast.TypeString,
   210  					},
   211  				},
   212  			},
   213  			false,
   214  		},
   215  
   216  		{
   217  			`foo ${foo("42", 42)}`,
   218  			&ast.BasicScope{
   219  				FuncMap: map[string]ast.Function{
   220  					"foo": ast.Function{
   221  						ArgTypes:     []ast.Type{ast.TypeString},
   222  						Variadic:     true,
   223  						VariadicType: ast.TypeString,
   224  						ReturnType:   ast.TypeString,
   225  					},
   226  				},
   227  			},
   228  			false,
   229  		},
   230  	}
   231  
   232  	for _, tc := range cases {
   233  		node, err := Parse(tc.Input)
   234  		if err != nil {
   235  			t.Fatalf("Error: %s\n\nInput: %s", err, tc.Input)
   236  		}
   237  
   238  		// Modify the scope to add our conversion functions.
   239  		if tc.Scope.FuncMap == nil {
   240  			tc.Scope.FuncMap = make(map[string]ast.Function)
   241  		}
   242  		tc.Scope.FuncMap["intToString"] = ast.Function{
   243  			ArgTypes:   []ast.Type{ast.TypeInt},
   244  			ReturnType: ast.TypeString,
   245  		}
   246  
   247  		// Do the first pass...
   248  		visitor := &TypeCheck{Scope: tc.Scope, Implicit: implicitMap}
   249  		err = visitor.Visit(node)
   250  		if (err != nil) != tc.Error {
   251  			t.Fatalf("Error: %s\n\nInput: %s", err, tc.Input)
   252  		}
   253  		if err != nil {
   254  			continue
   255  		}
   256  
   257  		// If we didn't error, then the next type check should not fail
   258  		// WITHOUT implicits.
   259  		visitor = &TypeCheck{Scope: tc.Scope}
   260  		err = visitor.Visit(node)
   261  		if err != nil {
   262  			t.Fatalf("Error: %s\n\nInput: %s", err, tc.Input)
   263  		}
   264  	}
   265  }