json/parser: empty list value should not flatten

Fixes https://github.com/hashicorp/terraform/issues/8886

While parsing JSON, an empty list value would be assumed to be a
non-existent list of objects, and would be removed from the result. This
may have never been the correct behavior but always worked okay because
we previously didn't support lists as first class types.

With the support of lists, we need to actually return the empty list as
the type. If we return nothing, then projects like Terraform will think
that the value was never set, which is false.
This commit is contained in:
Mitchell Hashimoto 2016-10-25 10:44:39 -07:00
parent 6f5bfed9a0
commit c03d57b578
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 48 additions and 12 deletions

View File

@ -274,6 +274,14 @@ func TestDecode_interface(t *testing.T) {
},
},
{
"structure_list_empty.json",
false,
map[string]interface{}{
"foo": []interface{}{},
},
},
{
"nested_block_comment.hcl",
false,

View File

@ -48,6 +48,12 @@ func flattenListType(
item *ast.ObjectItem,
items []*ast.ObjectItem,
frontier []*ast.ObjectItem) ([]*ast.ObjectItem, []*ast.ObjectItem) {
// If the list is empty, keep the original list
if len(ot.List) == 0 {
items = append(items, item)
return items, frontier
}
// All the elements of this object must also be objects!
for _, subitem := range ot.List {
if _, ok := subitem.(*ast.ObjectType); !ok {

View File

@ -86,6 +86,7 @@ func (p *Parser) objectList() (*ast.ObjectList, error) {
break
}
}
return node, nil
}

View File

@ -186,13 +186,13 @@ func TestFlattenObjects(t *testing.T) {
}{
{
`{
"foo": [
{
"foo": "svh",
"bar": "fatih"
}
]
}`,
"foo": [
{
"foo": "svh",
"bar": "fatih"
}
]
}`,
[]ast.Node{
&ast.ObjectType{},
&ast.LiteralType{},
@ -202,15 +202,33 @@ func TestFlattenObjects(t *testing.T) {
},
{
`{
"variable": {
"foo": {}
}
}`,
"variable": {
"foo": {}
}
}`,
[]ast.Node{
&ast.ObjectType{},
},
1,
},
{
`{
"empty": []
}`,
[]ast.Node{
&ast.ListType{},
},
1,
},
{
`{
"basic": [1, 2, 3]
}`,
[]ast.Node{
&ast.ListType{},
},
1,
},
}
for _, l := range literals {
@ -360,7 +378,7 @@ func TestParse_inline(t *testing.T) {
func equals(tb testing.TB, exp, act interface{}) {
if !reflect.DeepEqual(exp, act) {
_, file, line, _ := runtime.Caller(1)
fmt.Printf("\033[31m%s:%d:\n\n\texp: %#v\n\n\tgot: %#v\033[39m\n\n", filepath.Base(file), line, exp, act)
fmt.Printf("\033[31m%s:%d:\n\n\texp: %s\n\n\tgot: %s\033[39m\n\n", filepath.Base(file), line, exp, act)
tb.FailNow()
}
}

View File

@ -0,0 +1,3 @@
{
"foo": []
}