From b12d28fd16a802829fcbe1bac9a0143e183d0a1e Mon Sep 17 00:00:00 2001 From: Antti Kupila Date: Thu, 10 Jan 2019 08:43:00 +0100 Subject: [PATCH] hclpack: fix hclpack decoding nested body Fixes an issue where a nested block would be decoded incorrectly, the body of the last decoded block overwrites the previously decoded ones. This was caused by the block being assigned on the stack in the for loop; when the block is converted to a *hcl.Block, the pointer to Body will always point to the same block. This caused decoding a new block to overwrite the bodies of any previously decoded blocks. --- hclpack/structure.go | 4 +++ hclpack/structure_test.go | 75 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/hclpack/structure.go b/hclpack/structure.go index 3f51660..2721d26 100644 --- a/hclpack/structure.go +++ b/hclpack/structure.go @@ -114,6 +114,10 @@ func (b *Body) content(schema *hcl.BodySchema, remain *Body) (*hcl.BodyContent, var blocks []*hcl.Block for _, block := range b.ChildBlocks { + // Redeclare block on stack so the pointer to the body is set on the + // correct block. https://github.com/hashicorp/hcl2/issues/72 + block := block + blockTy := block.Type blockS, wanted := blocksWanted[blockTy] if !wanted { diff --git a/hclpack/structure_test.go b/hclpack/structure_test.go index 0d5f11c..78b1037 100644 --- a/hclpack/structure_test.go +++ b/hclpack/structure_test.go @@ -75,6 +75,73 @@ func TestBodyContent(t *testing.T) { }, }, }, + "block attributes": { + &Body{ + ChildBlocks: []Block{ + { + Type: "foo", + Body: Body{ + Attributes: map[string]Attribute{ + "bar": { + Expr: Expression{ + Source: []byte(`"hello"`), + SourceType: ExprNative, + }, + }, + }, + }, + }, + { + Type: "foo", + Body: Body{ + Attributes: map[string]Attribute{ + "bar": { + Expr: Expression{ + Source: []byte(`"world"`), + SourceType: ExprNative, + }, + }, + }, + }, + }, + }, + }, + &hcl.BodySchema{ + Blocks: []hcl.BlockHeaderSchema{ + {Type: "foo"}, + }, + }, + &hcl.BodyContent{ + Blocks: hcl.Blocks{ + { + Type: "foo", + Body: &Body{ + Attributes: map[string]Attribute{ + "bar": { + Expr: Expression{ + Source: []byte(`"hello"`), + SourceType: ExprNative, + }, + }, + }, + }, + }, + { + Type: "foo", + Body: &Body{ + Attributes: map[string]Attribute{ + "bar": { + Expr: Expression{ + Source: []byte(`"world"`), + SourceType: ExprNative, + }, + }, + }, + }, + }, + }, + }, + }, } for name, test := range tests { @@ -85,7 +152,13 @@ func TestBodyContent(t *testing.T) { } if !cmp.Equal(test.Want, got) { - t.Errorf("wrong result\n%s", cmp.Diff(test.Want, got)) + bytesAsString := func(s []byte) string { + return string(s) + } + t.Errorf("wrong result\n%s", cmp.Diff( + test.Want, got, + cmp.Transformer("bytesAsString", bytesAsString), + )) } }) }