Skip to content

Commit

Permalink
correctly populate default values
Browse files Browse the repository at this point in the history
  • Loading branch information
lovromazgon committed Apr 11, 2024
1 parent 784e856 commit 05db2b5
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 25 deletions.
48 changes: 28 additions & 20 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"errors"
"fmt"
"reflect"
"slices"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -50,8 +51,6 @@ func (c Config) Sanitize() Config {
func (c Config) ApplyDefaults(params Parameters) Config {
for key, param := range params {
for _, key := range c.getKeysForParameter(key) {
// TODO it's not that easy, we need to check for all keys with the
// same pattern and create them if they don't exist
if strings.TrimSpace(c[key]) == "" {
c[key] = param.Default
}
Expand Down Expand Up @@ -87,6 +86,7 @@ func (c Config) Validate(params Parameters) error {
func (c Config) validateUnrecognizedParameters(params Parameters) []error {
var errs []error
for key := range c {
// TODO dynamic parameters
if _, ok := params[key]; !ok {
errs = append(errs, fmt.Errorf("%q: %w", key, ErrUnrecognizedParameter))
}
Expand Down Expand Up @@ -135,10 +135,8 @@ func (c Config) validateParamType(key string, param Parameter) error {
// validateParamValue validates that a configuration value matches all the
// validations required for the parameter.
func (c Config) validateParamValue(key string, param Parameter) error {
keys := c.getKeysForParameter(key)

var errs []error
for _, k := range keys {
for _, k := range c.getKeysForParameter(key) {
value := c[k]
var valErrs []error

Expand Down Expand Up @@ -184,34 +182,44 @@ func (c Config) getKeysForParameter(key string) []string {
for k := range c {
fullKey := k
for i, token := range tokens {
var ok bool
k, ok = consume(k, token)
if !ok {
// The key does not start with the token, it does not match the pattern.
break
}
if i == len(tokens)-1 {
if k != "" && token != "" {
// The key is not fully consumed and last token is not a wildcard,
// it does not match the pattern.
if k == "" && token != "" {
// The key is consumed, but the token is not, it does not match the pattern.
// This happens when the last token is not a wildcard and
// the key is a leaf.
break
}
// We checked all tokens and the key matches the pattern.
// The last token doesn't matter, if the key matched so far, all
// wildcards have matched and we can potentially expect a match.
// The reason for this is so that we can apply defaults to the
// wildcard keys, even if they don't contain a value in the
// configuration.
if token != "" {
// Build potential key
fullKey = strings.TrimSuffix(fullKey, k)
fullKey += token
}
keys = append(keys, fullKey)
break
}

var ok bool
k, ok = consume(k, token)
if !ok {
// The key does not start with the token, it does not match the pattern.
break
}

// Between tokens there is a wildcard, we need to strip the key until
// the next ".".
_, k, ok = strings.Cut(k, ".")
if !ok {
// The key does not have a "." after the token, it does not match the pattern.
break
if ok {
k = "." + k // Add the "." back to the key.
}
k = "." + k // Add the "." back to the key.
}
}
return keys
slices.Sort(keys)
return slices.Compact(keys)
}

// DecodeInto copies configuration values into the target object.
Expand Down
31 changes: 26 additions & 5 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"testing"
"time"

"github.com/google/go-cmp/cmp"
"github.com/matryer/is"
)

Expand Down Expand Up @@ -611,6 +612,12 @@ func TestConfig_getValuesForParameter(t *testing.T) {

"test.bar.format.qux.type": "0",
"test.bar.format.qux.options": "0",

// include
"test.include.me": "yes",

// ignore this, it's not nested
"test.ignore": "0",
}

testCases := []struct {
Expand All @@ -623,8 +630,16 @@ func TestConfig_getValuesForParameter(t *testing.T) {
key: "blah",
want: []string{"blah"},
}, {
key: "test.*.blah",
want: nil,
key: "test.*.blah",
want: []string{
// Note that the function returns keys that don't exist in the config,
// it figures out the potential keys based on matched wildcards.
// However, it does not return test.ignore.blah, as test.ignore does
// not contain any nested keys.
"test.foo.blah",
"test.bar.blah",
"test.include.blah",
},
}, {
key: "test.*",
want: []string{
Expand All @@ -638,10 +653,16 @@ func TestConfig_getValuesForParameter(t *testing.T) {
"test.bar.format.baz.options",
"test.bar.format.qux.type",
"test.bar.format.qux.options",
"test.include.me",
"test.ignore",
},
}, {
key: "test.*.val",
want: []string{"test.foo.val", "test.bar.val"},
key: "test.*.val",
want: []string{
"test.foo.val",
"test.bar.val",
"test.include.val",
},
}, {
key: "test.*.format.*",
want: []string{
Expand Down Expand Up @@ -679,7 +700,7 @@ func TestConfig_getValuesForParameter(t *testing.T) {

sort.Strings(tc.want)
sort.Strings(got)
is.Equal(tc.want, got)
is.Equal(cmp.Diff(tc.want, got), "")
})
}

Expand Down

0 comments on commit 05db2b5

Please sign in to comment.