Skip to content

Commit

Permalink
correctly detect unrecognized parameters, lots of tests
Browse files Browse the repository at this point in the history
  • Loading branch information
lovromazgon committed Apr 11, 2024
1 parent 05db2b5 commit 3439261
Show file tree
Hide file tree
Showing 2 changed files with 363 additions and 12 deletions.
61 changes: 51 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,24 @@ 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 {
if _, ok := params[key]; ok {
// Direct match.
continue
}
// Check if the key is a wildcard key.
match := false
for pattern := range params {
if !strings.Contains(pattern, "*") {
continue
}
// Check if the key matches the wildcard key.
if c.matchParameterKey(key, pattern) {
match = true
break
}
}

if !match {
errs = append(errs, fmt.Errorf("%q: %w", key, ErrUnrecognizedParameter))
}
}
Expand Down Expand Up @@ -168,14 +184,6 @@ func (c Config) getKeysForParameter(key string) []string {
return []string{key}
}

consume := func(s, prefix string) (string, bool) {
if !strings.HasPrefix(s, prefix) {
// The key does not start with the token, it does not match the pattern.
return "", false
}
return strings.TrimPrefix(s, prefix), true
}

// There is at least one wildcard in the key, we need to manually find all
// the keys that match the pattern.
var keys []string
Expand All @@ -187,6 +195,7 @@ func (c Config) getKeysForParameter(key string) []string {
// 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.
// e.g. param: "collection.*.format", key: "collection.foo"
break
}
// The last token doesn't matter, if the key matched so far, all
Expand Down Expand Up @@ -222,6 +231,30 @@ func (c Config) getKeysForParameter(key string) []string {
return slices.Compact(keys)
}

func (c Config) matchParameterKey(key, pattern string) bool {
tokens := strings.Split(pattern, "*")
if len(tokens) == 1 {
// No wildcard in the key, compare the key directly.
return key == pattern
}
k := key
for _, token := range tokens {
var ok bool
k, ok = consume(k, token)
if !ok {
return false
}

// Between tokens there is a wildcard, we need to strip the key until
// the next ".".
_, k, ok = strings.Cut(k, ".")
if ok {
k = "." + k // Add the "." back to the key.
}
}
return true
}

// DecodeInto copies configuration values into the target object.
// Under the hood, this function uses github.com/mitchellh/mapstructure, with
// the "mapstructure" tag renamed to "json". To rename a key, use the "json"
Expand Down Expand Up @@ -341,3 +374,11 @@ func mapStructHookFunc() mapstructure.DecodeHookFunc {
return dataMap, nil
}
}

func consume(s, prefix string) (string, bool) {
if !strings.HasPrefix(s, prefix) {
// The key does not start with the token, it does not match the pattern.
return "", false
}
return strings.TrimPrefix(s, prefix), true
}
Loading

0 comments on commit 3439261

Please sign in to comment.