Merge pull request #275 from hashicorp/fix-unusedKeys

Fix unused keys
This commit is contained in:
Lang Martin 2019-04-30 09:52:23 -04:00 committed by GitHub
commit 99e2f22d1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 5 deletions

View File

@ -404,6 +404,11 @@ func (d *decoder) decodeMap(name string, node ast.Node, result reflect.Value) er
}
func (d *decoder) decodePtr(name string, node ast.Node, result reflect.Value) error {
// if pointer is not nil, decode into existing value
if !result.IsNil() {
return d.decode(name, node, result.Elem())
}
// Create an element of the concrete (non pointer) type and decode
// into that. Then set the value of the pointer to this type.
resultType := result.Type()
@ -512,7 +517,7 @@ func expandObject(node ast.Node, result reflect.Value) ast.Node {
// we need to un-flatten the ast enough to decode
newNode := &ast.ObjectItem{
Keys: []*ast.ObjectKey{
&ast.ObjectKey{
{
Token: keyToken,
},
},
@ -631,10 +636,19 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
}
}
usedKeys := make(map[string]struct{})
decodedFields := make([]string, 0, len(fields))
decodedFieldsVal := make([]reflect.Value, 0)
unusedKeysVal := make([]reflect.Value, 0)
// fill unusedNodeKeys with keys from the AST
// a slice because we have to do equals case fold to match Filter
unusedNodeKeys := make([]string, 0)
for _, item := range list.Items {
for _, k := range item.Keys {
unusedNodeKeys = append(unusedNodeKeys, k.Token.Value().(string))
}
}
for _, f := range fields {
field, fieldValue := f.field, f.val
if !fieldValue.IsValid() {
@ -689,8 +703,8 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
continue
}
// Track the used key
usedKeys[fieldName] = struct{}{}
// Track the used keys
unusedNodeKeys = removeCaseFold(unusedNodeKeys, fieldName)
// Create the field name and decode. We range over the elements
// because we actually want the value.
@ -723,6 +737,14 @@ func (d *decoder) decodeStruct(name string, node ast.Node, result reflect.Value)
}
}
if len(unusedNodeKeys) > 0 {
// like decodedFields, populated the unusedKeys field(s)
sort.Strings(unusedNodeKeys)
for _, v := range unusedKeysVal {
v.Set(reflect.ValueOf(unusedNodeKeys))
}
}
return nil
}
@ -734,3 +756,12 @@ func findNodeType() reflect.Type {
value := reflect.ValueOf(nodeContainer).FieldByName("Node")
return value.Type()
}
func removeCaseFold(xs []string, y string) []string {
for i, x := range xs {
if strings.EqualFold(x, y) {
return append(xs[:i], xs[i+1:]...)
}
}
return xs
}

View File

@ -616,6 +616,35 @@ func TestDecode_structurePtr(t *testing.T) {
}
}
func TestDecode_nonNilStructurePtr(t *testing.T) {
type V struct {
Key int
Foo string
DontChange string
}
actual := &V{
Key: 42,
Foo: "foo",
DontChange: "don't change me",
}
err := Decode(&actual, testReadFile(t, "flat.hcl"))
if err != nil {
t.Fatalf("err: %s", err)
}
expected := &V{
Key: 7,
Foo: "bar",
DontChange: "don't change me",
}
if !reflect.DeepEqual(actual, expected) {
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.
@ -786,6 +815,36 @@ func TestDecode_structureMapInvalid(t *testing.T) {
}
}
func TestDecode_structureMapExtraKeys(t *testing.T) {
type hclVariable struct {
A int
B int
Found []string `hcl:",decodedFields"`
Extra []string `hcl:",unusedKeys"`
}
q := hclVariable{
A: 1,
B: 2,
Found: []string{"A", "B"},
Extra: []string{"extra1", "extra2"},
}
var p hclVariable
ast, _ := Parse(testReadFile(t, "structure_map_extra_keys.hcl"))
DecodeObject(&p, ast)
if !reflect.DeepEqual(p, q) {
t.Fatal("not equal")
}
var j hclVariable
ast, _ = Parse(testReadFile(t, "structure_map_extra_keys.json"))
DecodeObject(&j, ast)
if !reflect.DeepEqual(p, j) {
t.Fatal("not equal")
}
}
func TestDecode_interfaceNonPointer(t *testing.T) {
var value interface{}
err := Decode(value, testReadFile(t, "basic_int_string.hcl"))

View File

@ -240,7 +240,7 @@ func TestListType_lineComment(t *testing.T) {
comment := l.comment[i]
if (lt.LineComment == nil) != (comment == "") {
t.Fatalf("bad: %s", lt)
t.Fatalf("bad: %s", lt.Token.Value())
}
if comment == "" {

View File

@ -0,0 +1,4 @@
a = 1
b = 2
extra1 = 3
extra2 = 4

View File

@ -0,0 +1,6 @@
{
"a": 1,
"b": 2,
"extra1": 3,
"extra2": 4
}