helper/schema: limit ValidateFunc to primitives for now

I couldn't see a simple path get this working for Maps, Sets,
and Lists, so lets land it as a primitive-only schema feature.

I think validation on primitives comprises 80% of the use cases anyways.
This commit is contained in:
Paul Hinze 2015-06-11 07:06:30 -05:00
parent 49352db26f
commit a4912cc51f
2 changed files with 50 additions and 11 deletions

View File

@ -136,6 +136,8 @@ type Schema struct {
// logic. It is yielded the provided config value as an interface{} that is // logic. It is yielded the provided config value as an interface{} that is
// guaranteed to be of the proper Schema type, and it can yield warnings or // guaranteed to be of the proper Schema type, and it can yield warnings or
// errors based on inspection of that value. // errors based on inspection of that value.
//
// ValidateFunc currently only works for primitive types.
ValidateFunc SchemaValidateFunc ValidateFunc SchemaValidateFunc
} }
@ -513,6 +515,13 @@ func (m schemaMap) InternalValidate(topSchemaMap schemaMap) error {
} }
} }
} }
if v.ValidateFunc != nil {
switch v.Type {
case TypeList, TypeSet, TypeMap:
return fmt.Errorf("ValidateFunc is only supported on primitives.")
}
}
} }
return nil return nil
@ -1128,6 +1137,7 @@ func (m schemaMap) validatePrimitive(
return nil, nil return nil, nil
} }
var decoded interface{}
switch schema.Type { switch schema.Type {
case TypeBool: case TypeBool:
// Verify that we can parse this as the correct type // Verify that we can parse this as the correct type
@ -1135,28 +1145,36 @@ func (m schemaMap) validatePrimitive(
if err := mapstructure.WeakDecode(raw, &n); err != nil { if err := mapstructure.WeakDecode(raw, &n); err != nil {
return nil, []error{err} return nil, []error{err}
} }
decoded = n
case TypeInt: case TypeInt:
// Verify that we can parse this as an int // Verify that we can parse this as an int
var n int var n int
if err := mapstructure.WeakDecode(raw, &n); err != nil { if err := mapstructure.WeakDecode(raw, &n); err != nil {
return nil, []error{err} return nil, []error{err}
} }
decoded = n
case TypeFloat: case TypeFloat:
// Verify that we can parse this as an int // Verify that we can parse this as an int
var n float64 var n float64
if err := mapstructure.WeakDecode(raw, &n); err != nil { if err := mapstructure.WeakDecode(raw, &n); err != nil {
return nil, []error{err} return nil, []error{err}
} }
decoded = n
case TypeString: case TypeString:
// Verify that we can parse this as a string // Verify that we can parse this as a string
var n string var n string
if err := mapstructure.WeakDecode(raw, &n); err != nil { if err := mapstructure.WeakDecode(raw, &n); err != nil {
return nil, []error{err} return nil, []error{err}
} }
decoded = n
default: default:
panic(fmt.Sprintf("Unknown validation type: %#v", schema.Type)) panic(fmt.Sprintf("Unknown validation type: %#v", schema.Type))
} }
if schema.ValidateFunc != nil {
return schema.ValidateFunc(decoded)
}
return nil, nil return nil, nil
} }
@ -1186,16 +1204,6 @@ func (m schemaMap) validateType(
"%q: [REMOVED] %s", k, schema.Removed)) "%q: [REMOVED] %s", k, schema.Removed))
} }
if len(es) == 0 && schema.ValidateFunc != nil {
ws2, es2 := schema.ValidateFunc(raw)
for _, w := range ws2 {
ws = append(ws, fmt.Sprintf("%q: %s", k, w))
}
for _, e := range es2 {
es = append(es, fmt.Errorf("%q: %s", k, e))
}
}
return ws, es return ws, es
} }

View File

@ -2796,6 +2796,20 @@ func TestSchemaMap_InternalValidate(t *testing.T) {
}, },
false, false,
}, },
// ValidateFunc on non-primitive
{
map[string]*Schema{
"foo": &Schema{
Type: TypeMap,
Required: true,
ValidateFunc: func(v interface{}) (ws []string, es []error) {
return
},
},
},
true,
},
} }
for i, tc := range cases { for i, tc := range cases {
@ -3435,7 +3449,7 @@ func TestSchemaMap_Validate(t *testing.T) {
}, },
Err: true, Err: true,
Errors: []error{ Errors: []error{
fmt.Errorf(`"validate_me": something is not right here`), fmt.Errorf(`something is not right here`),
}, },
}, },
@ -3455,6 +3469,23 @@ func TestSchemaMap_Validate(t *testing.T) {
}, },
Err: true, Err: true,
}, },
"ValidateFunc gets decoded type": {
Schema: map[string]*Schema{
"maybe": &Schema{
Type: TypeBool,
Required: true,
ValidateFunc: func(v interface{}) (ws []string, es []error) {
if _, ok := v.(bool); !ok {
t.Fatalf("Expected bool, got: %#v", v)
}
return
},
},
},
Config: map[string]interface{}{
"maybe": "true",
},
},
} }
for tn, tc := range cases { for tn, tc := range cases {