github.com/mingfang/terraform@v0.11.12-beta1/helper/schema/field_writer_map_test.go (about) 1 package schema 2 3 import ( 4 "reflect" 5 "testing" 6 ) 7 8 func TestMapFieldWriter_impl(t *testing.T) { 9 var _ FieldWriter = new(MapFieldWriter) 10 } 11 12 func TestMapFieldWriter(t *testing.T) { 13 schema := map[string]*Schema{ 14 "bool": &Schema{Type: TypeBool}, 15 "int": &Schema{Type: TypeInt}, 16 "string": &Schema{Type: TypeString}, 17 "list": &Schema{ 18 Type: TypeList, 19 Elem: &Schema{Type: TypeString}, 20 }, 21 "listInt": &Schema{ 22 Type: TypeList, 23 Elem: &Schema{Type: TypeInt}, 24 }, 25 "listResource": &Schema{ 26 Type: TypeList, 27 Optional: true, 28 Computed: true, 29 Elem: &Resource{ 30 Schema: map[string]*Schema{ 31 "value": &Schema{ 32 Type: TypeInt, 33 Optional: true, 34 }, 35 }, 36 }, 37 }, 38 "map": &Schema{Type: TypeMap}, 39 "set": &Schema{ 40 Type: TypeSet, 41 Elem: &Schema{Type: TypeInt}, 42 Set: func(a interface{}) int { 43 return a.(int) 44 }, 45 }, 46 "setDeep": &Schema{ 47 Type: TypeSet, 48 Elem: &Resource{ 49 Schema: map[string]*Schema{ 50 "index": &Schema{Type: TypeInt}, 51 "value": &Schema{Type: TypeString}, 52 }, 53 }, 54 Set: func(a interface{}) int { 55 return a.(map[string]interface{})["index"].(int) 56 }, 57 }, 58 } 59 60 cases := map[string]struct { 61 Addr []string 62 Value interface{} 63 Err bool 64 Out map[string]string 65 }{ 66 "noexist": { 67 []string{"noexist"}, 68 42, 69 true, 70 map[string]string{}, 71 }, 72 73 "bool": { 74 []string{"bool"}, 75 false, 76 false, 77 map[string]string{ 78 "bool": "false", 79 }, 80 }, 81 82 "int": { 83 []string{"int"}, 84 42, 85 false, 86 map[string]string{ 87 "int": "42", 88 }, 89 }, 90 91 "string": { 92 []string{"string"}, 93 "42", 94 false, 95 map[string]string{ 96 "string": "42", 97 }, 98 }, 99 100 "string nil": { 101 []string{"string"}, 102 nil, 103 false, 104 map[string]string{ 105 "string": "", 106 }, 107 }, 108 109 "list of resources": { 110 []string{"listResource"}, 111 []interface{}{ 112 map[string]interface{}{ 113 "value": 80, 114 }, 115 }, 116 false, 117 map[string]string{ 118 "listResource.#": "1", 119 "listResource.0.value": "80", 120 }, 121 }, 122 123 "list of resources empty": { 124 []string{"listResource"}, 125 []interface{}{}, 126 false, 127 map[string]string{ 128 "listResource.#": "0", 129 }, 130 }, 131 132 "list of resources nil": { 133 []string{"listResource"}, 134 nil, 135 false, 136 map[string]string{ 137 "listResource.#": "0", 138 }, 139 }, 140 141 "list of strings": { 142 []string{"list"}, 143 []interface{}{"foo", "bar"}, 144 false, 145 map[string]string{ 146 "list.#": "2", 147 "list.0": "foo", 148 "list.1": "bar", 149 }, 150 }, 151 152 "list element": { 153 []string{"list", "0"}, 154 "string", 155 true, 156 map[string]string{}, 157 }, 158 159 "map": { 160 []string{"map"}, 161 map[string]interface{}{"foo": "bar"}, 162 false, 163 map[string]string{ 164 "map.%": "1", 165 "map.foo": "bar", 166 }, 167 }, 168 169 "map delete": { 170 []string{"map"}, 171 nil, 172 false, 173 map[string]string{ 174 "map": "", 175 }, 176 }, 177 178 "map element": { 179 []string{"map", "foo"}, 180 "bar", 181 true, 182 map[string]string{}, 183 }, 184 185 "set": { 186 []string{"set"}, 187 []interface{}{1, 2, 5}, 188 false, 189 map[string]string{ 190 "set.#": "3", 191 "set.1": "1", 192 "set.2": "2", 193 "set.5": "5", 194 }, 195 }, 196 197 "set nil": { 198 []string{"set"}, 199 nil, 200 false, 201 map[string]string{ 202 "set.#": "0", 203 }, 204 }, 205 206 "set resource": { 207 []string{"setDeep"}, 208 []interface{}{ 209 map[string]interface{}{ 210 "index": 10, 211 "value": "foo", 212 }, 213 map[string]interface{}{ 214 "index": 50, 215 "value": "bar", 216 }, 217 }, 218 false, 219 map[string]string{ 220 "setDeep.#": "2", 221 "setDeep.10.index": "10", 222 "setDeep.10.value": "foo", 223 "setDeep.50.index": "50", 224 "setDeep.50.value": "bar", 225 }, 226 }, 227 228 "set element": { 229 []string{"set", "5"}, 230 5, 231 true, 232 map[string]string{}, 233 }, 234 235 "full object": { 236 nil, 237 map[string]interface{}{ 238 "string": "foo", 239 "list": []interface{}{"foo", "bar"}, 240 }, 241 false, 242 map[string]string{ 243 "string": "foo", 244 "list.#": "2", 245 "list.0": "foo", 246 "list.1": "bar", 247 }, 248 }, 249 } 250 251 for name, tc := range cases { 252 w := &MapFieldWriter{Schema: schema} 253 err := w.WriteField(tc.Addr, tc.Value) 254 if err != nil != tc.Err { 255 t.Fatalf("%s: err: %s", name, err) 256 } 257 258 actual := w.Map() 259 if !reflect.DeepEqual(actual, tc.Out) { 260 t.Fatalf("%s: bad: %#v", name, actual) 261 } 262 } 263 } 264 265 func TestMapFieldWriterCleanSet(t *testing.T) { 266 schema := map[string]*Schema{ 267 "setDeep": &Schema{ 268 Type: TypeSet, 269 Elem: &Resource{ 270 Schema: map[string]*Schema{ 271 "index": &Schema{Type: TypeInt}, 272 "value": &Schema{Type: TypeString}, 273 }, 274 }, 275 Set: func(a interface{}) int { 276 return a.(map[string]interface{})["index"].(int) 277 }, 278 }, 279 } 280 281 values := []struct { 282 Addr []string 283 Value interface{} 284 Out map[string]string 285 }{ 286 { 287 []string{"setDeep"}, 288 []interface{}{ 289 map[string]interface{}{ 290 "index": 10, 291 "value": "foo", 292 }, 293 map[string]interface{}{ 294 "index": 50, 295 "value": "bar", 296 }, 297 }, 298 map[string]string{ 299 "setDeep.#": "2", 300 "setDeep.10.index": "10", 301 "setDeep.10.value": "foo", 302 "setDeep.50.index": "50", 303 "setDeep.50.value": "bar", 304 }, 305 }, 306 { 307 []string{"setDeep"}, 308 []interface{}{ 309 map[string]interface{}{ 310 "index": 20, 311 "value": "baz", 312 }, 313 map[string]interface{}{ 314 "index": 60, 315 "value": "qux", 316 }, 317 }, 318 map[string]string{ 319 "setDeep.#": "2", 320 "setDeep.20.index": "20", 321 "setDeep.20.value": "baz", 322 "setDeep.60.index": "60", 323 "setDeep.60.value": "qux", 324 }, 325 }, 326 { 327 []string{"setDeep"}, 328 []interface{}{ 329 map[string]interface{}{ 330 "index": 30, 331 "value": "one", 332 }, 333 map[string]interface{}{ 334 "index": 70, 335 "value": "two", 336 }, 337 }, 338 map[string]string{ 339 "setDeep.#": "2", 340 "setDeep.30.index": "30", 341 "setDeep.30.value": "one", 342 "setDeep.70.index": "70", 343 "setDeep.70.value": "two", 344 }, 345 }, 346 } 347 348 w := &MapFieldWriter{Schema: schema} 349 350 for n, tc := range values { 351 err := w.WriteField(tc.Addr, tc.Value) 352 if err != nil { 353 t.Fatalf("%d: err: %s", n, err) 354 } 355 356 actual := w.Map() 357 if !reflect.DeepEqual(actual, tc.Out) { 358 t.Fatalf("%d: bad: %#v", n, actual) 359 } 360 } 361 } 362 363 func TestMapFieldWriterCleanList(t *testing.T) { 364 schema := map[string]*Schema{ 365 "listDeep": &Schema{ 366 Type: TypeList, 367 Elem: &Resource{ 368 Schema: map[string]*Schema{ 369 "thing1": &Schema{Type: TypeString}, 370 "thing2": &Schema{Type: TypeString}, 371 }, 372 }, 373 }, 374 } 375 376 values := []struct { 377 Addr []string 378 Value interface{} 379 Out map[string]string 380 }{ 381 { 382 // Base list 383 []string{"listDeep"}, 384 []interface{}{ 385 map[string]interface{}{ 386 "thing1": "a", 387 "thing2": "b", 388 }, 389 map[string]interface{}{ 390 "thing1": "c", 391 "thing2": "d", 392 }, 393 map[string]interface{}{ 394 "thing1": "e", 395 "thing2": "f", 396 }, 397 map[string]interface{}{ 398 "thing1": "g", 399 "thing2": "h", 400 }, 401 }, 402 map[string]string{ 403 "listDeep.#": "4", 404 "listDeep.0.thing1": "a", 405 "listDeep.0.thing2": "b", 406 "listDeep.1.thing1": "c", 407 "listDeep.1.thing2": "d", 408 "listDeep.2.thing1": "e", 409 "listDeep.2.thing2": "f", 410 "listDeep.3.thing1": "g", 411 "listDeep.3.thing2": "h", 412 }, 413 }, 414 { 415 // Remove an element 416 []string{"listDeep"}, 417 []interface{}{ 418 map[string]interface{}{ 419 "thing1": "a", 420 "thing2": "b", 421 }, 422 map[string]interface{}{ 423 "thing1": "c", 424 "thing2": "d", 425 }, 426 map[string]interface{}{ 427 "thing1": "e", 428 "thing2": "f", 429 }, 430 }, 431 map[string]string{ 432 "listDeep.#": "3", 433 "listDeep.0.thing1": "a", 434 "listDeep.0.thing2": "b", 435 "listDeep.1.thing1": "c", 436 "listDeep.1.thing2": "d", 437 "listDeep.2.thing1": "e", 438 "listDeep.2.thing2": "f", 439 }, 440 }, 441 { 442 // Rewrite with missing keys. This should normally not be necessary, as 443 // hopefully the writers are writing zero values as necessary, but for 444 // brevity we want to make sure that what exists in the writer is exactly 445 // what the last write looked like coming from the provider. 446 []string{"listDeep"}, 447 []interface{}{ 448 map[string]interface{}{ 449 "thing1": "a", 450 }, 451 map[string]interface{}{ 452 "thing1": "c", 453 }, 454 map[string]interface{}{ 455 "thing1": "e", 456 }, 457 }, 458 map[string]string{ 459 "listDeep.#": "3", 460 "listDeep.0.thing1": "a", 461 "listDeep.1.thing1": "c", 462 "listDeep.2.thing1": "e", 463 }, 464 }, 465 } 466 467 w := &MapFieldWriter{Schema: schema} 468 469 for n, tc := range values { 470 err := w.WriteField(tc.Addr, tc.Value) 471 if err != nil { 472 t.Fatalf("%d: err: %s", n, err) 473 } 474 475 actual := w.Map() 476 if !reflect.DeepEqual(actual, tc.Out) { 477 t.Fatalf("%d: bad: %#v", n, actual) 478 } 479 } 480 } 481 482 func TestMapFieldWriterCleanMap(t *testing.T) { 483 schema := map[string]*Schema{ 484 "map": &Schema{ 485 Type: TypeMap, 486 }, 487 } 488 489 values := []struct { 490 Value interface{} 491 Out map[string]string 492 }{ 493 { 494 // Base map 495 map[string]interface{}{ 496 "thing1": "a", 497 "thing2": "b", 498 "thing3": "c", 499 "thing4": "d", 500 }, 501 map[string]string{ 502 "map.%": "4", 503 "map.thing1": "a", 504 "map.thing2": "b", 505 "map.thing3": "c", 506 "map.thing4": "d", 507 }, 508 }, 509 { 510 // Base map 511 map[string]interface{}{ 512 "thing1": "a", 513 "thing2": "b", 514 "thing4": "d", 515 }, 516 map[string]string{ 517 "map.%": "3", 518 "map.thing1": "a", 519 "map.thing2": "b", 520 "map.thing4": "d", 521 }, 522 }, 523 } 524 525 w := &MapFieldWriter{Schema: schema} 526 527 for n, tc := range values { 528 err := w.WriteField([]string{"map"}, tc.Value) 529 if err != nil { 530 t.Fatalf("%d: err: %s", n, err) 531 } 532 533 actual := w.Map() 534 if !reflect.DeepEqual(actual, tc.Out) { 535 t.Fatalf("%d: bad: %#v", n, actual) 536 } 537 } 538 }