diff --git a/decoder.go b/decoder.go index 1b3125e..02759c0 100644 --- a/decoder.go +++ b/decoder.go @@ -277,7 +277,8 @@ func (d *decoder) decodePtr(name string, raw ast.Node, result reflect.Value) err func (d *decoder) decodeSlice(name string, raw ast.Node, result reflect.Value) error { n, ok := raw.(ast.ListNode) if !ok { - return fmt.Errorf("%s: not a list type", name) + // If it isn't a list, we turn it into one + n = ast.ListNode{Elem: []ast.Node{raw}} } // If we have an interface, then we can address the interface, diff --git a/decoder_test.go b/decoder_test.go index 6f4095c..f747ebb 100644 --- a/decoder_test.go +++ b/decoder_test.go @@ -183,3 +183,49 @@ func TestDecode_structurePtr(t *testing.T) { t.Fatalf("Actual: %#v\n\nExpected: %#v", actual, expected) } } + +func TestDecode_structureArray(t *testing.T) { + // This test is extracted from a failure in Consul (consul.io), + // hence the interesting structure naming. + + type KeyPolicy struct { + Prefix string `hcl:",key"` + Policy string + } + + type Policy struct { + Keys []KeyPolicy `hcl:"key"` + } + + var actual Policy + + err := Decode(&actual, testReadFile(t, "decode_policy.hcl")) + if err != nil { + t.Fatalf("err: %s", err) + } + + expected := Policy{ + Keys: []KeyPolicy{ + KeyPolicy{ + Prefix: "", + Policy: "read", + }, + KeyPolicy{ + Prefix: "foo/", + Policy: "write", + }, + KeyPolicy{ + Prefix: "foo/bar/", + Policy: "read", + }, + KeyPolicy{ + Prefix: "foo/bar/baz", + Policy: "deny", + }, + }, + } + + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("Actual: %#v\n\nExpected: %#v", actual, expected) + } +} diff --git a/test-fixtures/decode_policy.hcl b/test-fixtures/decode_policy.hcl new file mode 100644 index 0000000..7ed797b --- /dev/null +++ b/test-fixtures/decode_policy.hcl @@ -0,0 +1,15 @@ +key "" { + policy = "read" +} + +key "foo/" { + policy = "write" +} + +key "foo/bar/" { + policy = "read" +} + +key "foo/bar/baz" { + polizy = "deny" +}