From d18887aa89196bd27c63457b03814a5bf197a5a9 Mon Sep 17 00:00:00 2001 From: per1234 Date: Tue, 31 Aug 2021 12:21:02 -0700 Subject: [PATCH] Fix properties mapping utility function handling of overlapping keys The Arduino project configuration fields have an odd usage of the properties.Map format. Dots may sometimes indicate nested keys, but in other cases they are merely a character in the key string. Previously, the utility function used to recursively map to a configurable depth was not correctly handling this situation due to using the same code both for the recursive mapping to subkeys as well as for the flat mapping at the final depth. The fix for the bug also makes the function more efficient by avoiding calling SubTree() when it's already known there is no subtree. --- internal/project/general/general.go | 23 ++++++++++----------- internal/project/general/general_test.go | 26 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/internal/project/general/general.go b/internal/project/general/general.go index 416a7585..6cefa62a 100644 --- a/internal/project/general/general.go +++ b/internal/project/general/general.go @@ -32,20 +32,19 @@ In the event a full recursion of key levels is desired, set the levels argument func PropertiesToMap(flatProperties *properties.Map, levels int) map[string]interface{} { propertiesInterface := make(map[string]interface{}) - var keys []string if levels != 1 { - keys = flatProperties.FirstLevelKeys() + for _, key := range flatProperties.FirstLevelKeys() { + subTree := flatProperties.SubTree(key) + if subTree.Size() > 0 { + // This key contains a map. + propertiesInterface[key] = PropertiesToMap(subTree, levels-1) + } else { + // This key contains a string, no more recursion is possible. + propertiesInterface[key] = flatProperties.Get(key) + } + } } else { - keys = flatProperties.Keys() - } - - for _, key := range keys { - subTree := flatProperties.SubTree(key) - if subTree.Size() > 0 { - // This key contains a map. - propertiesInterface[key] = PropertiesToMap(subTree, levels-1) - } else { - // This key contains a string, no more recursion is possible. + for _, key := range flatProperties.Keys() { propertiesInterface[key] = flatProperties.Get(key) } } diff --git a/internal/project/general/general_test.go b/internal/project/general/general_test.go index dc6e3391..bb4c5ba1 100644 --- a/internal/project/general/general_test.go +++ b/internal/project/general/general_test.go @@ -31,6 +31,10 @@ func TestPropertiesToMap(t *testing.T) { foo.bar=asdf foo.baz=zxcv bar.bat.bam=123 + qux.a=x + qux.a.b=y + fuz.a.b=y + fuz.a=x `) propertiesInput, err := properties.LoadFromBytes(rawProperties) require.Nil(t, err) @@ -41,6 +45,10 @@ func TestPropertiesToMap(t *testing.T) { "foo.bar": "asdf", "foo.baz": "zxcv", "bar.bat.bam": "123", + "qux.a": "x", + "qux.a.b": "y", + "fuz.a.b": "y", + "fuz.a": "x", } assert.True(t, reflect.DeepEqual(expectedMapOutput, PropertiesToMap(propertiesInput, 1))) @@ -55,6 +63,14 @@ func TestPropertiesToMap(t *testing.T) { "bar": map[string]interface{}{ "bat.bam": "123", }, + "qux": map[string]interface{}{ + "a": "x", + "a.b": "y", + }, + "fuz": map[string]interface{}{ + "a.b": "y", + "a": "x", + }, } assert.True(t, reflect.DeepEqual(expectedMapOutput, PropertiesToMap(propertiesInput, 2))) @@ -71,6 +87,16 @@ func TestPropertiesToMap(t *testing.T) { "bam": "123", }, }, + "qux": map[string]interface{}{ + "a": map[string]interface{}{ + "b": "y", // It is impossible to represent the complete "properties" data structure recursed to this depth. + }, + }, + "fuz": map[string]interface{}{ + "a": map[string]interface{}{ + "b": "y", + }, + }, } assert.True(t, reflect.DeepEqual(expectedMapOutput, PropertiesToMap(propertiesInput, 3)))