github.com/muratcelep/terraform@v1.1.0-beta2-not-internal-4/not-internal/configs/hcl2shim/values_test.go (about) 1 package hcl2shim 2 3 import ( 4 "fmt" 5 "reflect" 6 "testing" 7 8 "github.com/muratcelep/terraform/not-internal/configs/configschema" 9 "github.com/zclconf/go-cty/cty" 10 ) 11 12 func TestConfigValueFromHCL2Block(t *testing.T) { 13 tests := []struct { 14 Input cty.Value 15 Schema *configschema.Block 16 Want map[string]interface{} 17 }{ 18 { 19 cty.ObjectVal(map[string]cty.Value{ 20 "name": cty.StringVal("Ermintrude"), 21 "age": cty.NumberIntVal(19), 22 "address": cty.ObjectVal(map[string]cty.Value{ 23 "street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}), 24 "city": cty.StringVal("Fridgewater"), 25 "state": cty.StringVal("MA"), 26 "zip": cty.StringVal("91037"), 27 }), 28 }), 29 &configschema.Block{ 30 Attributes: map[string]*configschema.Attribute{ 31 "name": {Type: cty.String, Optional: true}, 32 "age": {Type: cty.Number, Optional: true}, 33 }, 34 BlockTypes: map[string]*configschema.NestedBlock{ 35 "address": { 36 Nesting: configschema.NestingSingle, 37 Block: configschema.Block{ 38 Attributes: map[string]*configschema.Attribute{ 39 "street": {Type: cty.List(cty.String), Optional: true}, 40 "city": {Type: cty.String, Optional: true}, 41 "state": {Type: cty.String, Optional: true}, 42 "zip": {Type: cty.String, Optional: true}, 43 }, 44 }, 45 }, 46 }, 47 }, 48 map[string]interface{}{ 49 "name": "Ermintrude", 50 "age": int(19), 51 "address": map[string]interface{}{ 52 "street": []interface{}{"421 Shoreham Loop"}, 53 "city": "Fridgewater", 54 "state": "MA", 55 "zip": "91037", 56 }, 57 }, 58 }, 59 { 60 cty.ObjectVal(map[string]cty.Value{ 61 "name": cty.StringVal("Ermintrude"), 62 "age": cty.NumberIntVal(19), 63 "address": cty.NullVal(cty.Object(map[string]cty.Type{ 64 "street": cty.List(cty.String), 65 "city": cty.String, 66 "state": cty.String, 67 "zip": cty.String, 68 })), 69 }), 70 &configschema.Block{ 71 Attributes: map[string]*configschema.Attribute{ 72 "name": {Type: cty.String, Optional: true}, 73 "age": {Type: cty.Number, Optional: true}, 74 }, 75 BlockTypes: map[string]*configschema.NestedBlock{ 76 "address": { 77 Nesting: configschema.NestingSingle, 78 Block: configschema.Block{ 79 Attributes: map[string]*configschema.Attribute{ 80 "street": {Type: cty.List(cty.String), Optional: true}, 81 "city": {Type: cty.String, Optional: true}, 82 "state": {Type: cty.String, Optional: true}, 83 "zip": {Type: cty.String, Optional: true}, 84 }, 85 }, 86 }, 87 }, 88 }, 89 map[string]interface{}{ 90 "name": "Ermintrude", 91 "age": int(19), 92 }, 93 }, 94 { 95 cty.ObjectVal(map[string]cty.Value{ 96 "name": cty.StringVal("Ermintrude"), 97 "age": cty.NumberIntVal(19), 98 "address": cty.ObjectVal(map[string]cty.Value{ 99 "street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}), 100 "city": cty.StringVal("Fridgewater"), 101 "state": cty.StringVal("MA"), 102 "zip": cty.NullVal(cty.String), // should be omitted altogether in result 103 }), 104 }), 105 &configschema.Block{ 106 Attributes: map[string]*configschema.Attribute{ 107 "name": {Type: cty.String, Optional: true}, 108 "age": {Type: cty.Number, Optional: true}, 109 }, 110 BlockTypes: map[string]*configschema.NestedBlock{ 111 "address": { 112 Nesting: configschema.NestingSingle, 113 Block: configschema.Block{ 114 Attributes: map[string]*configschema.Attribute{ 115 "street": {Type: cty.List(cty.String), Optional: true}, 116 "city": {Type: cty.String, Optional: true}, 117 "state": {Type: cty.String, Optional: true}, 118 "zip": {Type: cty.String, Optional: true}, 119 }, 120 }, 121 }, 122 }, 123 }, 124 map[string]interface{}{ 125 "name": "Ermintrude", 126 "age": int(19), 127 "address": map[string]interface{}{ 128 "street": []interface{}{"421 Shoreham Loop"}, 129 "city": "Fridgewater", 130 "state": "MA", 131 }, 132 }, 133 }, 134 { 135 cty.ObjectVal(map[string]cty.Value{ 136 "address": cty.ListVal([]cty.Value{cty.EmptyObjectVal}), 137 }), 138 &configschema.Block{ 139 BlockTypes: map[string]*configschema.NestedBlock{ 140 "address": { 141 Nesting: configschema.NestingList, 142 Block: configschema.Block{}, 143 }, 144 }, 145 }, 146 map[string]interface{}{ 147 "address": []interface{}{ 148 map[string]interface{}{}, 149 }, 150 }, 151 }, 152 { 153 cty.ObjectVal(map[string]cty.Value{ 154 "address": cty.ListValEmpty(cty.EmptyObject), // should be omitted altogether in result 155 }), 156 &configschema.Block{ 157 BlockTypes: map[string]*configschema.NestedBlock{ 158 "address": { 159 Nesting: configschema.NestingList, 160 Block: configschema.Block{}, 161 }, 162 }, 163 }, 164 map[string]interface{}{}, 165 }, 166 { 167 cty.ObjectVal(map[string]cty.Value{ 168 "address": cty.SetVal([]cty.Value{cty.EmptyObjectVal}), 169 }), 170 &configschema.Block{ 171 BlockTypes: map[string]*configschema.NestedBlock{ 172 "address": { 173 Nesting: configschema.NestingSet, 174 Block: configschema.Block{}, 175 }, 176 }, 177 }, 178 map[string]interface{}{ 179 "address": []interface{}{ 180 map[string]interface{}{}, 181 }, 182 }, 183 }, 184 { 185 cty.ObjectVal(map[string]cty.Value{ 186 "address": cty.SetValEmpty(cty.EmptyObject), 187 }), 188 &configschema.Block{ 189 BlockTypes: map[string]*configschema.NestedBlock{ 190 "address": { 191 Nesting: configschema.NestingSet, 192 Block: configschema.Block{}, 193 }, 194 }, 195 }, 196 map[string]interface{}{}, 197 }, 198 { 199 cty.ObjectVal(map[string]cty.Value{ 200 "address": cty.MapVal(map[string]cty.Value{"foo": cty.EmptyObjectVal}), 201 }), 202 &configschema.Block{ 203 BlockTypes: map[string]*configschema.NestedBlock{ 204 "address": { 205 Nesting: configschema.NestingMap, 206 Block: configschema.Block{}, 207 }, 208 }, 209 }, 210 map[string]interface{}{ 211 "address": map[string]interface{}{ 212 "foo": map[string]interface{}{}, 213 }, 214 }, 215 }, 216 { 217 cty.ObjectVal(map[string]cty.Value{ 218 "address": cty.MapValEmpty(cty.EmptyObject), 219 }), 220 &configschema.Block{ 221 BlockTypes: map[string]*configschema.NestedBlock{ 222 "address": { 223 Nesting: configschema.NestingMap, 224 Block: configschema.Block{}, 225 }, 226 }, 227 }, 228 map[string]interface{}{}, 229 }, 230 { 231 cty.NullVal(cty.EmptyObject), 232 &configschema.Block{}, 233 nil, 234 }, 235 } 236 237 for _, test := range tests { 238 t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) { 239 got := ConfigValueFromHCL2Block(test.Input, test.Schema) 240 if !reflect.DeepEqual(got, test.Want) { 241 t.Errorf("wrong result\ninput: %#v\ngot: %#v\nwant: %#v", test.Input, got, test.Want) 242 } 243 }) 244 } 245 } 246 247 func TestConfigValueFromHCL2(t *testing.T) { 248 tests := []struct { 249 Input cty.Value 250 Want interface{} 251 }{ 252 { 253 cty.True, 254 true, 255 }, 256 { 257 cty.False, 258 false, 259 }, 260 { 261 cty.NumberIntVal(12), 262 int(12), 263 }, 264 { 265 cty.NumberFloatVal(12.5), 266 float64(12.5), 267 }, 268 { 269 cty.StringVal("hello world"), 270 "hello world", 271 }, 272 { 273 cty.ObjectVal(map[string]cty.Value{ 274 "name": cty.StringVal("Ermintrude"), 275 "age": cty.NumberIntVal(19), 276 "address": cty.ObjectVal(map[string]cty.Value{ 277 "street": cty.ListVal([]cty.Value{cty.StringVal("421 Shoreham Loop")}), 278 "city": cty.StringVal("Fridgewater"), 279 "state": cty.StringVal("MA"), 280 "zip": cty.StringVal("91037"), 281 }), 282 }), 283 map[string]interface{}{ 284 "name": "Ermintrude", 285 "age": int(19), 286 "address": map[string]interface{}{ 287 "street": []interface{}{"421 Shoreham Loop"}, 288 "city": "Fridgewater", 289 "state": "MA", 290 "zip": "91037", 291 }, 292 }, 293 }, 294 { 295 cty.MapVal(map[string]cty.Value{ 296 "foo": cty.StringVal("bar"), 297 "bar": cty.StringVal("baz"), 298 }), 299 map[string]interface{}{ 300 "foo": "bar", 301 "bar": "baz", 302 }, 303 }, 304 { 305 cty.TupleVal([]cty.Value{ 306 cty.StringVal("foo"), 307 cty.True, 308 }), 309 []interface{}{ 310 "foo", 311 true, 312 }, 313 }, 314 { 315 cty.NullVal(cty.String), 316 nil, 317 }, 318 { 319 cty.UnknownVal(cty.String), 320 UnknownVariableValue, 321 }, 322 } 323 324 for _, test := range tests { 325 t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) { 326 got := ConfigValueFromHCL2(test.Input) 327 if !reflect.DeepEqual(got, test.Want) { 328 t.Errorf("wrong result\ninput: %#v\ngot: %#v\nwant: %#v", test.Input, got, test.Want) 329 } 330 }) 331 } 332 } 333 334 func TestHCL2ValueFromConfigValue(t *testing.T) { 335 tests := []struct { 336 Input interface{} 337 Want cty.Value 338 }{ 339 { 340 nil, 341 cty.NullVal(cty.DynamicPseudoType), 342 }, 343 { 344 UnknownVariableValue, 345 cty.DynamicVal, 346 }, 347 { 348 true, 349 cty.True, 350 }, 351 { 352 false, 353 cty.False, 354 }, 355 { 356 int(12), 357 cty.NumberIntVal(12), 358 }, 359 { 360 int(0), 361 cty.Zero, 362 }, 363 { 364 float64(12.5), 365 cty.NumberFloatVal(12.5), 366 }, 367 { 368 "hello world", 369 cty.StringVal("hello world"), 370 }, 371 { 372 "O\u0308", // decomposed letter + diacritic 373 cty.StringVal("\u00D6"), // NFC-normalized on entry into cty 374 }, 375 { 376 []interface{}{}, 377 cty.EmptyTupleVal, 378 }, 379 { 380 []interface{}(nil), 381 cty.EmptyTupleVal, 382 }, 383 { 384 []interface{}{"hello", "world"}, 385 cty.TupleVal([]cty.Value{cty.StringVal("hello"), cty.StringVal("world")}), 386 }, 387 { 388 map[string]interface{}{}, 389 cty.EmptyObjectVal, 390 }, 391 { 392 map[string]interface{}(nil), 393 cty.EmptyObjectVal, 394 }, 395 { 396 map[string]interface{}{ 397 "foo": "bar", 398 "bar": "baz", 399 }, 400 cty.ObjectVal(map[string]cty.Value{ 401 "foo": cty.StringVal("bar"), 402 "bar": cty.StringVal("baz"), 403 }), 404 }, 405 } 406 407 for _, test := range tests { 408 t.Run(fmt.Sprintf("%#v", test.Input), func(t *testing.T) { 409 got := HCL2ValueFromConfigValue(test.Input) 410 if !got.RawEquals(test.Want) { 411 t.Errorf("wrong result\ninput: %#v\ngot: %#v\nwant: %#v", test.Input, got, test.Want) 412 } 413 }) 414 } 415 }