authelia/internal/configuration/schema/validator.go
Amir Zarrinkafsh 54694c4fca
[MISC] Ignore errcheck recommendations for legacy code (#893)
* [MISC] Ignore errcheck recommendations for legacy code
Some of this is likely intended to stay how it is, some could use refactoring, for now we will mark is and ignore it from the linter to be potentially addressed in the future.

* [MISC] Ensure files are gofmt-ed
2020-04-22 13:33:14 +10:00

135 lines
3.2 KiB
Go

package schema
import (
"fmt"
"reflect"
"github.com/Workiva/go-datastructures/queue"
)
// ErrorContainer represents a container where we can add errors and retrieve them
type ErrorContainer interface {
Push(err error)
HasErrors() bool
Errors() []error
}
// Validator represents the validator interface
type Validator struct {
errors map[string][]error
}
// NewValidator create a validator
func NewValidator() *Validator {
validator := new(Validator)
validator.errors = make(map[string][]error)
return validator
}
// QueueItem an item representing a struct field and its path.
type QueueItem struct {
value reflect.Value
path string
}
func (v *Validator) validateOne(item QueueItem, q *queue.Queue) error { //nolint:unparam
if item.value.Type().Kind() == reflect.Ptr {
if item.value.IsNil() {
return nil
}
elem := item.value.Elem()
q.Put(QueueItem{ //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
value: elem,
path: item.path,
})
} else if item.value.Kind() == reflect.Struct {
numFields := item.value.Type().NumField()
validateFn := item.value.Addr().MethodByName("Validate")
if validateFn.IsValid() {
structValidator := NewStructValidator()
validateFn.Call([]reflect.Value{reflect.ValueOf(structValidator)})
v.errors[item.path] = structValidator.Errors()
}
for i := 0; i < numFields; i++ {
field := item.value.Type().Field(i)
value := item.value.Field(i)
q.Put(QueueItem{ //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
value: value,
path: item.path + "." + field.Name,
})
}
}
return nil
}
// Validate validate a struct
func (v *Validator) Validate(s interface{}) error {
q := queue.New(40)
q.Put(QueueItem{value: reflect.ValueOf(s), path: "root"}) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
for !q.Empty() {
val, err := q.Get(1)
if err != nil {
return err
}
item, ok := val[0].(QueueItem)
if !ok {
return fmt.Errorf("Cannot convert item into QueueItem")
}
v.validateOne(item, q) //nolint:errcheck // TODO: Legacy code, consider refactoring time permitting.
}
return nil
}
// PrintErrors display the errors thrown during validation
func (v *Validator) PrintErrors() {
for path, errs := range v.errors {
fmt.Printf("Errors at %s:\n", path)
for _, err := range errs {
fmt.Printf("--> %s\n", err)
}
}
}
// Errors return the errors thrown during validation
func (v *Validator) Errors() map[string][]error {
return v.errors
}
// StructValidator is a validator for structs
type StructValidator struct {
errors []error
}
// NewStructValidator is a constructor of struct validator
func NewStructValidator() *StructValidator {
val := new(StructValidator)
val.errors = make([]error, 0)
return val
}
// Push an error in the validator.
func (v *StructValidator) Push(err error) {
v.errors = append(v.errors, err)
}
// HasErrors checks whether the validator contains errors.
func (v *StructValidator) HasErrors() bool {
return len(v.errors) > 0
}
// Errors returns the errors.
func (v *StructValidator) Errors() []error {
return v.errors
}
// Clear errors
func (v *StructValidator) Clear() {
v.errors = []error{}
}