github.com/KevinKlinger/open_terraform@v0.11.12-beta1/config/configschema/decoder_spec_test.go (about) 1 package configschema 2 3 import ( 4 "testing" 5 6 "github.com/davecgh/go-spew/spew" 7 8 "github.com/hashicorp/hcl2/hcl" 9 "github.com/hashicorp/hcl2/hcldec" 10 "github.com/hashicorp/hcl2/hcltest" 11 "github.com/zclconf/go-cty/cty" 12 ) 13 14 func TestBlockDecoderSpec(t *testing.T) { 15 tests := map[string]struct { 16 Schema *Block 17 TestBody hcl.Body 18 Want cty.Value 19 DiagCount int 20 }{ 21 "empty": { 22 &Block{}, 23 hcl.EmptyBody(), 24 cty.EmptyObjectVal, 25 0, 26 }, 27 "nil": { 28 nil, 29 hcl.EmptyBody(), 30 cty.EmptyObjectVal, 31 0, 32 }, 33 "attributes": { 34 &Block{ 35 Attributes: map[string]*Attribute{ 36 "optional": { 37 Type: cty.Number, 38 Optional: true, 39 }, 40 "required": { 41 Type: cty.String, 42 Required: true, 43 }, 44 "computed": { 45 Type: cty.List(cty.Bool), 46 Computed: true, 47 }, 48 "optional_computed": { 49 Type: cty.Map(cty.Bool), 50 Optional: true, 51 Computed: true, 52 }, 53 "optional_computed_overridden": { 54 Type: cty.Bool, 55 Optional: true, 56 Computed: true, 57 }, 58 }, 59 }, 60 hcltest.MockBody(&hcl.BodyContent{ 61 Attributes: hcl.Attributes{ 62 "required": { 63 Name: "required", 64 Expr: hcltest.MockExprLiteral(cty.NumberIntVal(5)), 65 }, 66 "optional_computed_overridden": { 67 Name: "optional_computed_overridden", 68 Expr: hcltest.MockExprLiteral(cty.True), 69 }, 70 }, 71 }), 72 cty.ObjectVal(map[string]cty.Value{ 73 "optional": cty.NullVal(cty.Number), 74 "required": cty.StringVal("5"), // converted from number to string 75 "computed": cty.UnknownVal(cty.List(cty.Bool)), 76 "optional_computed": cty.UnknownVal(cty.Map(cty.Bool)), 77 "optional_computed_overridden": cty.True, 78 }), 79 0, 80 }, 81 "dynamically-typed attribute": { 82 &Block{ 83 Attributes: map[string]*Attribute{ 84 "foo": { 85 Type: cty.DynamicPseudoType, // any type is permitted 86 Required: true, 87 }, 88 }, 89 }, 90 hcltest.MockBody(&hcl.BodyContent{ 91 Attributes: hcl.Attributes{ 92 "foo": { 93 Name: "foo", 94 Expr: hcltest.MockExprLiteral(cty.True), 95 }, 96 }, 97 }), 98 cty.ObjectVal(map[string]cty.Value{ 99 "foo": cty.True, 100 }), 101 0, 102 }, 103 "dynamically-typed attribute omitted": { 104 &Block{ 105 Attributes: map[string]*Attribute{ 106 "foo": { 107 Type: cty.DynamicPseudoType, // any type is permitted 108 Optional: true, 109 }, 110 }, 111 }, 112 hcltest.MockBody(&hcl.BodyContent{}), 113 cty.ObjectVal(map[string]cty.Value{ 114 "foo": cty.NullVal(cty.DynamicPseudoType), 115 }), 116 0, 117 }, 118 "required attribute omitted": { 119 &Block{ 120 Attributes: map[string]*Attribute{ 121 "foo": { 122 Type: cty.Bool, 123 Required: true, 124 }, 125 }, 126 }, 127 hcltest.MockBody(&hcl.BodyContent{}), 128 cty.ObjectVal(map[string]cty.Value{ 129 "foo": cty.NullVal(cty.Bool), 130 }), 131 1, // missing required attribute 132 }, 133 "wrong attribute type": { 134 &Block{ 135 Attributes: map[string]*Attribute{ 136 "optional": { 137 Type: cty.Number, 138 Optional: true, 139 }, 140 }, 141 }, 142 hcltest.MockBody(&hcl.BodyContent{ 143 Attributes: hcl.Attributes{ 144 "optional": { 145 Name: "optional", 146 Expr: hcltest.MockExprLiteral(cty.True), 147 }, 148 }, 149 }), 150 cty.ObjectVal(map[string]cty.Value{ 151 "optional": cty.UnknownVal(cty.Number), 152 }), 153 1, // incorrect type; number required 154 }, 155 "blocks": { 156 &Block{ 157 BlockTypes: map[string]*NestedBlock{ 158 "single": { 159 Nesting: NestingSingle, 160 Block: Block{}, 161 }, 162 "list": { 163 Nesting: NestingList, 164 Block: Block{}, 165 }, 166 "set": { 167 Nesting: NestingSet, 168 Block: Block{}, 169 }, 170 "map": { 171 Nesting: NestingMap, 172 Block: Block{}, 173 }, 174 }, 175 }, 176 hcltest.MockBody(&hcl.BodyContent{ 177 Blocks: hcl.Blocks{ 178 &hcl.Block{ 179 Type: "list", 180 Body: hcl.EmptyBody(), 181 }, 182 &hcl.Block{ 183 Type: "single", 184 Body: hcl.EmptyBody(), 185 }, 186 &hcl.Block{ 187 Type: "list", 188 Body: hcl.EmptyBody(), 189 }, 190 &hcl.Block{ 191 Type: "set", 192 Body: hcl.EmptyBody(), 193 }, 194 &hcl.Block{ 195 Type: "map", 196 Labels: []string{"foo"}, 197 LabelRanges: []hcl.Range{hcl.Range{}}, 198 Body: hcl.EmptyBody(), 199 }, 200 &hcl.Block{ 201 Type: "map", 202 Labels: []string{"bar"}, 203 LabelRanges: []hcl.Range{hcl.Range{}}, 204 Body: hcl.EmptyBody(), 205 }, 206 &hcl.Block{ 207 Type: "set", 208 Body: hcl.EmptyBody(), 209 }, 210 }, 211 }), 212 cty.ObjectVal(map[string]cty.Value{ 213 "single": cty.EmptyObjectVal, 214 "list": cty.ListVal([]cty.Value{ 215 cty.EmptyObjectVal, 216 cty.EmptyObjectVal, 217 }), 218 "set": cty.SetVal([]cty.Value{ 219 cty.EmptyObjectVal, 220 cty.EmptyObjectVal, 221 }), 222 "map": cty.MapVal(map[string]cty.Value{ 223 "foo": cty.EmptyObjectVal, 224 "bar": cty.EmptyObjectVal, 225 }), 226 }), 227 0, 228 }, 229 "too many list items": { 230 &Block{ 231 BlockTypes: map[string]*NestedBlock{ 232 "foo": { 233 Nesting: NestingList, 234 Block: Block{}, 235 MaxItems: 1, 236 }, 237 }, 238 }, 239 hcltest.MockBody(&hcl.BodyContent{ 240 Blocks: hcl.Blocks{ 241 &hcl.Block{ 242 Type: "foo", 243 Body: hcl.EmptyBody(), 244 }, 245 &hcl.Block{ 246 Type: "foo", 247 Body: hcl.EmptyBody(), 248 }, 249 }, 250 }), 251 cty.ObjectVal(map[string]cty.Value{ 252 "foo": cty.ListVal([]cty.Value{ 253 cty.EmptyObjectVal, 254 cty.EmptyObjectVal, 255 }), 256 }), 257 1, // too many "foo" blocks 258 }, 259 "extraneous attribute": { 260 &Block{}, 261 hcltest.MockBody(&hcl.BodyContent{ 262 Attributes: hcl.Attributes{ 263 "extra": { 264 Name: "extra", 265 Expr: hcltest.MockExprLiteral(cty.StringVal("hello")), 266 }, 267 }, 268 }), 269 cty.EmptyObjectVal, 270 1, // extraneous attribute 271 }, 272 } 273 274 for name, test := range tests { 275 t.Run(name, func(t *testing.T) { 276 spec := test.Schema.DecoderSpec() 277 got, diags := hcldec.Decode(test.TestBody, spec, nil) 278 if len(diags) != test.DiagCount { 279 t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount) 280 for _, diag := range diags { 281 t.Logf("- %s", diag.Error()) 282 } 283 } 284 285 if !got.RawEquals(test.Want) { 286 t.Logf("[INFO] implied schema is %s", spew.Sdump(hcldec.ImpliedSchema(spec))) 287 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 288 } 289 290 // Double-check that we're producing consistent results for DecoderSpec 291 // and ImpliedType. 292 impliedType := test.Schema.ImpliedType() 293 if errs := got.Type().TestConformance(impliedType); len(errs) != 0 { 294 t.Errorf("result does not conform to the schema's implied type") 295 for _, err := range errs { 296 t.Logf("- %s", err.Error()) 297 } 298 } 299 }) 300 } 301 }