diff --git a/changes/20240827111953.feature b/changes/20240827111953.feature new file mode 100644 index 0000000000..4b9a6c1d55 --- /dev/null +++ b/changes/20240827111953.feature @@ -0,0 +1 @@ +:sparkles: Add support for parsing a comma separated string list as a map of key-value pairs diff --git a/utils/collection/parseLists.go b/utils/collection/parseLists.go index 2e72395490..d2e2f95b1d 100644 --- a/utils/collection/parseLists.go +++ b/utils/collection/parseLists.go @@ -5,8 +5,11 @@ package collection import ( + "fmt" "strings" "unicode" + + "github.com/ARM-software/golang-utils/utils/commonerrors" ) func lineIsOnlyWhitespace(line string) bool { @@ -52,3 +55,22 @@ func ParseListWithCleanupKeepBlankLines(input string, sep string) (newS []string func ParseCommaSeparatedList(input string) []string { return ParseListWithCleanup(input, ",") } + +// ParseCommaSeparatedListToMap returns a map of key value pairs from a string containing a comma separated list +func ParseCommaSeparatedListToMap(input string) (pairs map[string]string, err error) { + inputSplit := ParseCommaSeparatedList(input) + numElements := len(inputSplit) + + if numElements%2 != 0 { + err = fmt.Errorf("%w: could not parse comma separated list '%v' into map as it did not have an even number of elements", commonerrors.ErrInvalid, input) + return + } + + pairs = make(map[string]string, numElements/2) + // TODO use slices.Chunk introduced in go 23 when library is upgraded + for i := 0; i < numElements; i += 2 { + pairs[inputSplit[i]] = inputSplit[i+1] + } + + return +} diff --git a/utils/collection/parseLists_test.go b/utils/collection/parseLists_test.go index 1a497f271e..6af5d22c0a 100644 --- a/utils/collection/parseLists_test.go +++ b/utils/collection/parseLists_test.go @@ -10,7 +10,12 @@ import ( "time" "github.com/go-faker/faker/v4" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/exp/maps" + + "github.com/ARM-software/golang-utils/utils/commonerrors" + "github.com/ARM-software/golang-utils/utils/commonerrors/errortest" ) var ( @@ -87,3 +92,36 @@ func TestParseCommaSeparatedListWithSpacesBetweenWordsKeepBlanks(t *testing.T) { finalList2 := ParseListWithCleanupKeepBlankLines(stringList, ",") require.Equal(t, stringArray, finalList2) } + +func TestParseCommaSeparatedListToMap(t *testing.T) { + for _, test := range []struct { + Name string + Input string + Expected map[string]string + Err error + }{ + {"Normal 1", "hello,world", map[string]string{"hello": "world"}, nil}, + {"Normal 2", "hello,world,adrien,cabarbaye", map[string]string{"hello": "world", "adrien": "cabarbaye"}, nil}, + {"Normal 2.5", "hello, world, adrien, cabarbaye", map[string]string{"hello": "world", "adrien": "cabarbaye"}, nil}, + {"Normal 3", "hello,world,adrien,cabarbaye,", map[string]string{"hello": "world", "adrien": "cabarbaye"}, nil}, + {"Normal 4", "hello,,world,adrien,,,cabarbaye,,,", map[string]string{"hello": "world", "adrien": "cabarbaye"}, nil}, + {"Normal 5", "hello,world,this,value has spaces", map[string]string{"hello": "world", "this": "value has spaces"}, nil}, + {"Normal 6", "hello,,world,this,,,value has spaces,,,", map[string]string{"hello": "world", "this": "value has spaces"}, nil}, + {"Normal 7", "", map[string]string{}, nil}, + {"Normal 8", ",", map[string]string{}, nil}, + {"Normal 9", ",,,,,", map[string]string{}, nil}, + {"Normal 10", ",, ,, ,", map[string]string{}, nil}, + {"Bad 1", "one", nil, commonerrors.ErrInvalid}, + {"Bad 1", "one, two, three", nil, commonerrors.ErrInvalid}, + {"Bad 2", "one element with spaces", nil, commonerrors.ErrInvalid}, + {"Bad 3", "one element with spaces and end comma,", nil, commonerrors.ErrInvalid}, + {"Bad 4", "one element with spaces and multiple end commas,,,", nil, commonerrors.ErrInvalid}, + {"Bad 5", ",,,one element with spaces and multiple end/beginning commas,,,", nil, commonerrors.ErrInvalid}, + } { + t.Run(test.Name, func(t *testing.T) { + pairs, err := ParseCommaSeparatedListToMap(test.Input) + errortest.AssertError(t, err, test.Err) + assert.True(t, maps.Equal(test.Expected, pairs)) + }) + } +}