github.com/terramate-io/tf@v0.0.0-20230830114523-fce866b4dfcd/legacy/helper/schema/field_reader_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package schema 5 6 import ( 7 "reflect" 8 "testing" 9 ) 10 11 func TestAddrToSchema(t *testing.T) { 12 cases := map[string]struct { 13 Addr []string 14 Schema map[string]*Schema 15 Result []ValueType 16 }{ 17 "full object": { 18 []string{}, 19 map[string]*Schema{ 20 "list": &Schema{ 21 Type: TypeList, 22 Elem: &Schema{Type: TypeInt}, 23 }, 24 }, 25 []ValueType{typeObject}, 26 }, 27 28 "list": { 29 []string{"list"}, 30 map[string]*Schema{ 31 "list": &Schema{ 32 Type: TypeList, 33 Elem: &Schema{Type: TypeInt}, 34 }, 35 }, 36 []ValueType{TypeList}, 37 }, 38 39 "list.#": { 40 []string{"list", "#"}, 41 map[string]*Schema{ 42 "list": &Schema{ 43 Type: TypeList, 44 Elem: &Schema{Type: TypeInt}, 45 }, 46 }, 47 []ValueType{TypeList, TypeInt}, 48 }, 49 50 "list.0": { 51 []string{"list", "0"}, 52 map[string]*Schema{ 53 "list": &Schema{ 54 Type: TypeList, 55 Elem: &Schema{Type: TypeInt}, 56 }, 57 }, 58 []ValueType{TypeList, TypeInt}, 59 }, 60 61 "list.0 with resource": { 62 []string{"list", "0"}, 63 map[string]*Schema{ 64 "list": &Schema{ 65 Type: TypeList, 66 Elem: &Resource{ 67 Schema: map[string]*Schema{ 68 "field": &Schema{Type: TypeString}, 69 }, 70 }, 71 }, 72 }, 73 []ValueType{TypeList, typeObject}, 74 }, 75 76 "list.0.field": { 77 []string{"list", "0", "field"}, 78 map[string]*Schema{ 79 "list": &Schema{ 80 Type: TypeList, 81 Elem: &Resource{ 82 Schema: map[string]*Schema{ 83 "field": &Schema{Type: TypeString}, 84 }, 85 }, 86 }, 87 }, 88 []ValueType{TypeList, typeObject, TypeString}, 89 }, 90 91 "set": { 92 []string{"set"}, 93 map[string]*Schema{ 94 "set": &Schema{ 95 Type: TypeSet, 96 Elem: &Schema{Type: TypeInt}, 97 Set: func(a interface{}) int { 98 return a.(int) 99 }, 100 }, 101 }, 102 []ValueType{TypeSet}, 103 }, 104 105 "set.#": { 106 []string{"set", "#"}, 107 map[string]*Schema{ 108 "set": &Schema{ 109 Type: TypeSet, 110 Elem: &Schema{Type: TypeInt}, 111 Set: func(a interface{}) int { 112 return a.(int) 113 }, 114 }, 115 }, 116 []ValueType{TypeSet, TypeInt}, 117 }, 118 119 "set.0": { 120 []string{"set", "0"}, 121 map[string]*Schema{ 122 "set": &Schema{ 123 Type: TypeSet, 124 Elem: &Schema{Type: TypeInt}, 125 Set: func(a interface{}) int { 126 return a.(int) 127 }, 128 }, 129 }, 130 []ValueType{TypeSet, TypeInt}, 131 }, 132 133 "set.0 with resource": { 134 []string{"set", "0"}, 135 map[string]*Schema{ 136 "set": &Schema{ 137 Type: TypeSet, 138 Elem: &Resource{ 139 Schema: map[string]*Schema{ 140 "field": &Schema{Type: TypeString}, 141 }, 142 }, 143 }, 144 }, 145 []ValueType{TypeSet, typeObject}, 146 }, 147 148 "mapElem": { 149 []string{"map", "foo"}, 150 map[string]*Schema{ 151 "map": &Schema{Type: TypeMap}, 152 }, 153 []ValueType{TypeMap, TypeString}, 154 }, 155 156 "setDeep": { 157 []string{"set", "50", "index"}, 158 map[string]*Schema{ 159 "set": &Schema{ 160 Type: TypeSet, 161 Elem: &Resource{ 162 Schema: map[string]*Schema{ 163 "index": &Schema{Type: TypeInt}, 164 "value": &Schema{Type: TypeString}, 165 }, 166 }, 167 Set: func(a interface{}) int { 168 return a.(map[string]interface{})["index"].(int) 169 }, 170 }, 171 }, 172 []ValueType{TypeSet, typeObject, TypeInt}, 173 }, 174 } 175 176 for name, tc := range cases { 177 result := addrToSchema(tc.Addr, tc.Schema) 178 types := make([]ValueType, len(result)) 179 for i, v := range result { 180 types[i] = v.Type 181 } 182 183 if !reflect.DeepEqual(types, tc.Result) { 184 t.Fatalf("%s: %#v", name, types) 185 } 186 } 187 } 188 189 // testFieldReader is a helper that should be used to verify that 190 // a FieldReader behaves properly in all the common cases. 191 func testFieldReader(t *testing.T, f func(map[string]*Schema) FieldReader) { 192 schema := map[string]*Schema{ 193 // Primitives 194 "bool": &Schema{Type: TypeBool}, 195 "float": &Schema{Type: TypeFloat}, 196 "int": &Schema{Type: TypeInt}, 197 "string": &Schema{Type: TypeString}, 198 199 // Lists 200 "list": &Schema{ 201 Type: TypeList, 202 Elem: &Schema{Type: TypeString}, 203 }, 204 "listInt": &Schema{ 205 Type: TypeList, 206 Elem: &Schema{Type: TypeInt}, 207 }, 208 "listMap": &Schema{ 209 Type: TypeList, 210 Elem: &Schema{ 211 Type: TypeMap, 212 }, 213 }, 214 215 // Maps 216 "map": &Schema{Type: TypeMap}, 217 "mapInt": &Schema{ 218 Type: TypeMap, 219 Elem: TypeInt, 220 }, 221 222 // This is used to verify that the type of a Map can be specified using the 223 // same syntax as for lists (as a nested *Schema passed to Elem) 224 "mapIntNestedSchema": &Schema{ 225 Type: TypeMap, 226 Elem: &Schema{Type: TypeInt}, 227 }, 228 "mapFloat": &Schema{ 229 Type: TypeMap, 230 Elem: TypeFloat, 231 }, 232 "mapBool": &Schema{ 233 Type: TypeMap, 234 Elem: TypeBool, 235 }, 236 237 // Sets 238 "set": &Schema{ 239 Type: TypeSet, 240 Elem: &Schema{Type: TypeInt}, 241 Set: func(a interface{}) int { 242 return a.(int) 243 }, 244 }, 245 "setDeep": &Schema{ 246 Type: TypeSet, 247 Elem: &Resource{ 248 Schema: map[string]*Schema{ 249 "index": &Schema{Type: TypeInt}, 250 "value": &Schema{Type: TypeString}, 251 }, 252 }, 253 Set: func(a interface{}) int { 254 return a.(map[string]interface{})["index"].(int) 255 }, 256 }, 257 "setEmpty": &Schema{ 258 Type: TypeSet, 259 Elem: &Schema{Type: TypeInt}, 260 Set: func(a interface{}) int { 261 return a.(int) 262 }, 263 }, 264 } 265 266 cases := map[string]struct { 267 Addr []string 268 Result FieldReadResult 269 Err bool 270 }{ 271 "noexist": { 272 []string{"boolNOPE"}, 273 FieldReadResult{ 274 Value: nil, 275 Exists: false, 276 Computed: false, 277 }, 278 false, 279 }, 280 281 "bool": { 282 []string{"bool"}, 283 FieldReadResult{ 284 Value: true, 285 Exists: true, 286 Computed: false, 287 }, 288 false, 289 }, 290 291 "float": { 292 []string{"float"}, 293 FieldReadResult{ 294 Value: 3.1415, 295 Exists: true, 296 Computed: false, 297 }, 298 false, 299 }, 300 301 "int": { 302 []string{"int"}, 303 FieldReadResult{ 304 Value: 42, 305 Exists: true, 306 Computed: false, 307 }, 308 false, 309 }, 310 311 "string": { 312 []string{"string"}, 313 FieldReadResult{ 314 Value: "string", 315 Exists: true, 316 Computed: false, 317 }, 318 false, 319 }, 320 321 "list": { 322 []string{"list"}, 323 FieldReadResult{ 324 Value: []interface{}{ 325 "foo", 326 "bar", 327 }, 328 Exists: true, 329 Computed: false, 330 }, 331 false, 332 }, 333 334 "listInt": { 335 []string{"listInt"}, 336 FieldReadResult{ 337 Value: []interface{}{ 338 21, 339 42, 340 }, 341 Exists: true, 342 Computed: false, 343 }, 344 false, 345 }, 346 347 "map": { 348 []string{"map"}, 349 FieldReadResult{ 350 Value: map[string]interface{}{ 351 "foo": "bar", 352 "bar": "baz", 353 }, 354 Exists: true, 355 Computed: false, 356 }, 357 false, 358 }, 359 360 "mapInt": { 361 []string{"mapInt"}, 362 FieldReadResult{ 363 Value: map[string]interface{}{ 364 "one": 1, 365 "two": 2, 366 }, 367 Exists: true, 368 Computed: false, 369 }, 370 false, 371 }, 372 373 "mapIntNestedSchema": { 374 []string{"mapIntNestedSchema"}, 375 FieldReadResult{ 376 Value: map[string]interface{}{ 377 "one": 1, 378 "two": 2, 379 }, 380 Exists: true, 381 Computed: false, 382 }, 383 false, 384 }, 385 386 "mapFloat": { 387 []string{"mapFloat"}, 388 FieldReadResult{ 389 Value: map[string]interface{}{ 390 "oneDotTwo": 1.2, 391 }, 392 Exists: true, 393 Computed: false, 394 }, 395 false, 396 }, 397 398 "mapBool": { 399 []string{"mapBool"}, 400 FieldReadResult{ 401 Value: map[string]interface{}{ 402 "True": true, 403 "False": false, 404 }, 405 Exists: true, 406 Computed: false, 407 }, 408 false, 409 }, 410 411 "mapelem": { 412 []string{"map", "foo"}, 413 FieldReadResult{ 414 Value: "bar", 415 Exists: true, 416 Computed: false, 417 }, 418 false, 419 }, 420 421 "set": { 422 []string{"set"}, 423 FieldReadResult{ 424 Value: []interface{}{10, 50}, 425 Exists: true, 426 Computed: false, 427 }, 428 false, 429 }, 430 431 "setDeep": { 432 []string{"setDeep"}, 433 FieldReadResult{ 434 Value: []interface{}{ 435 map[string]interface{}{ 436 "index": 10, 437 "value": "foo", 438 }, 439 map[string]interface{}{ 440 "index": 50, 441 "value": "bar", 442 }, 443 }, 444 Exists: true, 445 Computed: false, 446 }, 447 false, 448 }, 449 450 "setEmpty": { 451 []string{"setEmpty"}, 452 FieldReadResult{ 453 Value: []interface{}{}, 454 Exists: false, 455 }, 456 false, 457 }, 458 } 459 460 for name, tc := range cases { 461 r := f(schema) 462 out, err := r.ReadField(tc.Addr) 463 if err != nil != tc.Err { 464 t.Fatalf("%s: err: %s", name, err) 465 } 466 if s, ok := out.Value.(*Set); ok { 467 // If it is a set, convert to a list so its more easily checked. 468 out.Value = s.List() 469 } 470 if !reflect.DeepEqual(tc.Result, out) { 471 t.Fatalf("%s: bad: %#v", name, out) 472 } 473 } 474 }