github.com/jonasi/terraform@v0.6.10-0.20160125170522-e865c342cc1f/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 }