github.com/hashicorp/hcl/v2@v2.20.0/hcltest/mock_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package hcltest 5 6 import ( 7 "strings" 8 "testing" 9 10 "reflect" 11 12 "github.com/hashicorp/hcl/v2" 13 "github.com/zclconf/go-cty/cty" 14 ) 15 16 var mockBodyIsBody hcl.Body = mockBody{} 17 var mockExprLiteralIsExpr hcl.Expression = mockExprLiteral{} 18 var mockExprVariableIsExpr hcl.Expression = mockExprVariable("") 19 20 func TestMockBodyPartialContent(t *testing.T) { 21 tests := map[string]struct { 22 In *hcl.BodyContent 23 Schema *hcl.BodySchema 24 Want *hcl.BodyContent 25 Remain *hcl.BodyContent 26 DiagCount int 27 }{ 28 "empty": { 29 &hcl.BodyContent{}, 30 &hcl.BodySchema{}, 31 &hcl.BodyContent{ 32 Attributes: hcl.Attributes{}, 33 Blocks: hcl.Blocks{}, 34 }, 35 &hcl.BodyContent{ 36 Attributes: hcl.Attributes{}, 37 Blocks: hcl.Blocks{}, 38 }, 39 0, 40 }, 41 "attribute requested": { 42 &hcl.BodyContent{ 43 Attributes: MockAttrs(map[string]hcl.Expression{ 44 "name": MockExprLiteral(cty.StringVal("Ermintrude")), 45 }), 46 }, 47 &hcl.BodySchema{ 48 Attributes: []hcl.AttributeSchema{ 49 { 50 Name: "name", 51 }, 52 }, 53 }, 54 &hcl.BodyContent{ 55 Attributes: MockAttrs(map[string]hcl.Expression{ 56 "name": MockExprLiteral(cty.StringVal("Ermintrude")), 57 }), 58 Blocks: hcl.Blocks{}, 59 }, 60 &hcl.BodyContent{ 61 Attributes: hcl.Attributes{}, 62 Blocks: hcl.Blocks{}, 63 }, 64 0, 65 }, 66 "attribute remains": { 67 &hcl.BodyContent{ 68 Attributes: MockAttrs(map[string]hcl.Expression{ 69 "name": MockExprLiteral(cty.StringVal("Ermintrude")), 70 }), 71 }, 72 &hcl.BodySchema{}, 73 &hcl.BodyContent{ 74 Attributes: hcl.Attributes{}, 75 Blocks: hcl.Blocks{}, 76 }, 77 &hcl.BodyContent{ 78 Attributes: MockAttrs(map[string]hcl.Expression{ 79 "name": MockExprLiteral(cty.StringVal("Ermintrude")), 80 }), 81 Blocks: hcl.Blocks{}, 82 }, 83 0, 84 }, 85 "attribute missing": { 86 &hcl.BodyContent{ 87 Attributes: hcl.Attributes{}, 88 }, 89 &hcl.BodySchema{ 90 Attributes: []hcl.AttributeSchema{ 91 { 92 Name: "name", 93 Required: true, 94 }, 95 }, 96 }, 97 &hcl.BodyContent{ 98 Attributes: hcl.Attributes{}, 99 Blocks: hcl.Blocks{}, 100 }, 101 &hcl.BodyContent{ 102 Attributes: hcl.Attributes{}, 103 Blocks: hcl.Blocks{}, 104 }, 105 1, // missing attribute "name" 106 }, 107 "block requested, no labels": { 108 &hcl.BodyContent{ 109 Blocks: hcl.Blocks{ 110 { 111 Type: "baz", 112 }, 113 }, 114 }, 115 &hcl.BodySchema{ 116 Blocks: []hcl.BlockHeaderSchema{ 117 { 118 Type: "baz", 119 }, 120 }, 121 }, 122 &hcl.BodyContent{ 123 Attributes: hcl.Attributes{}, 124 Blocks: hcl.Blocks{ 125 { 126 Type: "baz", 127 }, 128 }, 129 }, 130 &hcl.BodyContent{ 131 Attributes: hcl.Attributes{}, 132 Blocks: hcl.Blocks{}, 133 }, 134 0, 135 }, 136 "block requested, wrong labels": { 137 &hcl.BodyContent{ 138 Blocks: hcl.Blocks{ 139 { 140 Type: "baz", 141 }, 142 }, 143 }, 144 &hcl.BodySchema{ 145 Blocks: []hcl.BlockHeaderSchema{ 146 { 147 Type: "baz", 148 LabelNames: []string{"foo"}, 149 }, 150 }, 151 }, 152 &hcl.BodyContent{ 153 Attributes: hcl.Attributes{}, 154 Blocks: hcl.Blocks{ 155 { 156 Type: "baz", 157 }, 158 }, 159 }, 160 &hcl.BodyContent{ 161 Attributes: hcl.Attributes{}, 162 Blocks: hcl.Blocks{}, 163 }, 164 1, // "baz" requires 1 label 165 }, 166 "block remains": { 167 &hcl.BodyContent{ 168 Blocks: hcl.Blocks{ 169 { 170 Type: "baz", 171 }, 172 }, 173 }, 174 &hcl.BodySchema{}, 175 &hcl.BodyContent{ 176 Attributes: hcl.Attributes{}, 177 Blocks: hcl.Blocks{}, 178 }, 179 &hcl.BodyContent{ 180 Attributes: hcl.Attributes{}, 181 Blocks: hcl.Blocks{ 182 { 183 Type: "baz", 184 }, 185 }, 186 }, 187 0, 188 }, 189 "various": { 190 &hcl.BodyContent{ 191 Attributes: MockAttrs(map[string]hcl.Expression{ 192 "name": MockExprLiteral(cty.StringVal("Ermintrude")), 193 "age": MockExprLiteral(cty.NumberIntVal(32)), 194 }), 195 Blocks: hcl.Blocks{ 196 { 197 Type: "baz", 198 }, 199 { 200 Type: "bar", 201 Labels: []string{"foo1"}, 202 }, 203 { 204 Type: "bar", 205 Labels: []string{"foo2"}, 206 }, 207 }, 208 }, 209 &hcl.BodySchema{ 210 Attributes: []hcl.AttributeSchema{ 211 { 212 Name: "name", 213 }, 214 }, 215 Blocks: []hcl.BlockHeaderSchema{ 216 { 217 Type: "bar", 218 LabelNames: []string{"name"}, 219 }, 220 }, 221 }, 222 &hcl.BodyContent{ 223 Attributes: MockAttrs(map[string]hcl.Expression{ 224 "name": MockExprLiteral(cty.StringVal("Ermintrude")), 225 }), 226 Blocks: hcl.Blocks{ 227 { 228 Type: "bar", 229 Labels: []string{"foo1"}, 230 }, 231 { 232 Type: "bar", 233 Labels: []string{"foo2"}, 234 }, 235 }, 236 }, 237 &hcl.BodyContent{ 238 Attributes: MockAttrs(map[string]hcl.Expression{ 239 "age": MockExprLiteral(cty.NumberIntVal(32)), 240 }), 241 Blocks: hcl.Blocks{ 242 { 243 Type: "baz", 244 }, 245 }, 246 }, 247 0, 248 }, 249 } 250 251 for name, test := range tests { 252 t.Run(name, func(t *testing.T) { 253 inBody := MockBody(test.In) 254 got, remainBody, diags := inBody.PartialContent(test.Schema) 255 if len(diags) != test.DiagCount { 256 t.Errorf("wrong number of diagnostics %d; want %d", len(diags), test.DiagCount) 257 for _, diag := range diags { 258 t.Logf("- %s", diag) 259 } 260 } 261 262 if !reflect.DeepEqual(got, test.Want) { 263 t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want) 264 } 265 266 gotRemain := remainBody.(mockBody).C 267 if !reflect.DeepEqual(gotRemain, test.Remain) { 268 t.Errorf("wrong remain\ngot: %#v\nwant: %#v", gotRemain, test.Remain) 269 } 270 }) 271 } 272 } 273 274 func TestExprList(t *testing.T) { 275 tests := map[string]struct { 276 In hcl.Expression 277 Want []hcl.Expression 278 Diags string 279 }{ 280 "as list": { 281 In: MockExprLiteral(cty.ListVal([]cty.Value{ 282 cty.StringVal("foo"), 283 cty.StringVal("bar"), 284 })), 285 Want: []hcl.Expression{ 286 MockExprLiteral(cty.StringVal("foo")), 287 MockExprLiteral(cty.StringVal("bar")), 288 }, 289 }, 290 "as tuple": { 291 In: MockExprLiteral(cty.TupleVal([]cty.Value{ 292 cty.StringVal("foo"), 293 cty.StringVal("bar"), 294 })), 295 Want: []hcl.Expression{ 296 MockExprLiteral(cty.StringVal("foo")), 297 MockExprLiteral(cty.StringVal("bar")), 298 }, 299 }, 300 "not list": { 301 In: MockExprLiteral(cty.ObjectVal(map[string]cty.Value{ 302 "a": cty.StringVal("foo"), 303 "b": cty.StringVal("bar"), 304 })), 305 Want: nil, 306 Diags: "list expression is required", 307 }, 308 } 309 310 for name, tc := range tests { 311 t.Run(name, func(t *testing.T) { 312 got, diags := hcl.ExprList(tc.In) 313 if tc.Diags != "" { 314 if diags.HasErrors() && !strings.Contains(diags.Error(), tc.Diags) { 315 t.Errorf("expected error %q, got %q", tc.Diags, diags) 316 } 317 if !diags.HasErrors() { 318 t.Errorf("expected diagnostic message %q", tc.Diags) 319 } 320 } else if diags.HasErrors() { 321 t.Error(diags) 322 } 323 324 if !reflect.DeepEqual(got, tc.Want) { 325 t.Errorf("incorrect expression,\ngot: %#v\nwant: %#v", got, tc.Want) 326 } 327 }) 328 } 329 } 330 331 func TestExprMap(t *testing.T) { 332 tests := map[string]struct { 333 In hcl.Expression 334 Want []hcl.KeyValuePair 335 Diags string 336 }{ 337 "as object": { 338 In: MockExprLiteral(cty.ObjectVal(map[string]cty.Value{ 339 "name": cty.StringVal("test"), 340 "count": cty.NumberIntVal(2), 341 })), 342 Want: []hcl.KeyValuePair{ 343 { 344 Key: MockExprLiteral(cty.StringVal("count")), 345 Value: MockExprLiteral(cty.NumberIntVal(2)), 346 }, 347 { 348 Key: MockExprLiteral(cty.StringVal("name")), 349 Value: MockExprLiteral(cty.StringVal("test")), 350 }, 351 }, 352 }, 353 "as map": { 354 In: MockExprLiteral(cty.MapVal(map[string]cty.Value{ 355 "name": cty.StringVal("test"), 356 "version": cty.StringVal("2.0.0"), 357 })), 358 Want: []hcl.KeyValuePair{ 359 { 360 Key: MockExprLiteral(cty.StringVal("name")), 361 Value: MockExprLiteral(cty.StringVal("test")), 362 }, 363 { 364 Key: MockExprLiteral(cty.StringVal("version")), 365 Value: MockExprLiteral(cty.StringVal("2.0.0")), 366 }, 367 }, 368 }, 369 "not map": { 370 In: MockExprLiteral(cty.ListVal([]cty.Value{ 371 cty.StringVal("foo"), 372 cty.StringVal("bar"), 373 })), 374 Want: nil, 375 Diags: "map expression is required", 376 }, 377 } 378 379 for name, tc := range tests { 380 t.Run(name, func(t *testing.T) { 381 got, diags := hcl.ExprMap(tc.In) 382 if tc.Diags != "" { 383 if diags.HasErrors() && !strings.Contains(diags.Error(), tc.Diags) { 384 t.Errorf("expected error %q, got %q", tc.Diags, diags) 385 } 386 if !diags.HasErrors() { 387 t.Errorf("expected diagnostic message %q", tc.Diags) 388 } 389 } else if diags.HasErrors() { 390 t.Error(diags) 391 } 392 393 if !reflect.DeepEqual(got, tc.Want) { 394 t.Errorf("incorrect expression,\ngot: %#v\nwant: %#v", got, tc.Want) 395 } 396 }) 397 } 398 }