diff --git a/formats.go b/formats.go index 78e8639..9c66cab 100644 --- a/formats.go +++ b/formats.go @@ -55,7 +55,7 @@ func (f *formatValidator) SetPath(path string) { } func (f *formatValidator) Applies(source interface{}, kind reflect.Kind) bool { - if source == nil { + if source == nil || f.KnownFormats == nil { return false } @@ -74,7 +74,7 @@ func (f *formatValidator) Applies(source interface{}, kind reflect.Kind) bool { } func (f *formatValidator) Validate(val interface{}) *Result { - if f.Options.recycleValidators && !f.Options.skipRedeemOnValidate { + if f.Options.recycleValidators { defer func() { f.redeem() }() diff --git a/formats_test.go b/formats_test.go index aa1be19..751efb3 100644 --- a/formats_test.go +++ b/formats_test.go @@ -13,9 +13,10 @@ import ( // Validator for string formats func TestFormatValidator_EdgeCases(t *testing.T) { // Apply - v := formatValidator{ - KnownFormats: strfmt.Default, - } + v := newFormatValidator( + "", "", "", strfmt.Default, nil, + ) + v.SetPath("a.b.c") // formatValidator applies to: Items, Parameter,Schema diff --git a/go.mod b/go.mod index d097c17..03c9d4a 100644 --- a/go.mod +++ b/go.mod @@ -1,7 +1,5 @@ module github.com/go-openapi/validate -replace github.com/go-openapi/swag => github.com/fredbi/swag v0.22.8-fred2 - require ( github.com/go-openapi/analysis v0.22.0 github.com/go-openapi/errors v0.21.0 @@ -9,7 +7,7 @@ require ( github.com/go-openapi/loads v0.21.5 github.com/go-openapi/spec v0.20.14 github.com/go-openapi/strfmt v0.22.0 - github.com/go-openapi/swag v0.22.7 + github.com/go-openapi/swag v0.22.8 github.com/stretchr/testify v1.8.4 gopkg.in/yaml.v3 v3.0.1 ) diff --git a/go.sum b/go.sum index e4650d8..ea4eb72 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,6 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3d github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fredbi/swag v0.22.8-fred2 h1:6mm1vWEsjFhgiI0XIUjgR+YkpklZYDPxGLgFcGtIE/0= -github.com/fredbi/swag v0.22.8-fred2/go.mod h1:6QT22icPLEqAM/z/TChgb4WAveCHF92+2gF0CNjHpPI= github.com/go-openapi/analysis v0.22.0 h1:wQ/d07nf78HNj4u+KiSY0sT234IAyePPbMgpUjUJQR0= github.com/go-openapi/analysis v0.22.0/go.mod h1:acDnkkCI2QxIo8sSIPgmp1wUlRohV7vfGtAIVae73b0= github.com/go-openapi/errors v0.21.0 h1:FhChC/duCnfoLj1gZ0BgaBmzhJC2SL/sJr8a2vAobSY= @@ -18,6 +16,8 @@ github.com/go-openapi/spec v0.20.14 h1:7CBlRnw+mtjFGlPDRZmAMnq35cRzI91xj03HVyUi/ github.com/go-openapi/spec v0.20.14/go.mod h1:8EOhTpBoFiask8rrgwbLC3zmJfz4zsCUueRuPM6GNkw= github.com/go-openapi/strfmt v0.22.0 h1:Ew9PnEYc246TwrEspvBdDHS4BVKXy/AOVsfqGDgAcaI= github.com/go-openapi/strfmt v0.22.0/go.mod h1:HzJ9kokGIju3/K6ap8jL+OlGAbjpSv27135Yr9OivU4= +github.com/go-openapi/swag v0.22.8 h1:/9RjDSQ0vbFR+NyjGMkFTsA1IA0fmhKSThmfGZjicbw= +github.com/go-openapi/swag v0.22.8/go.mod h1:6QT22icPLEqAM/z/TChgb4WAveCHF92+2gF0CNjHpPI= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= diff --git a/object_validator.go b/object_validator.go index 998bbf3..1867b70 100644 --- a/object_validator.go +++ b/object_validator.go @@ -44,14 +44,14 @@ func newObjectValidator(path, in string, additionalProperties *spec.SchemaOrBool, patternProperties spec.SchemaProperties, root interface{}, formats strfmt.Registry, opts *SchemaValidatorOptions) *objectValidator { if opts == nil { - opts = &SchemaValidatorOptions{} + opts = new(SchemaValidatorOptions) } var v *objectValidator if opts.recycleValidators { v = poolOfObjectValidators.BorrowValidator() } else { - v = &objectValidator{} + v = new(objectValidator) } v.Path = path @@ -138,7 +138,7 @@ func (o *objectValidator) precheck(res *Result, val map[string]interface{}) { } func (o *objectValidator) Validate(data interface{}) *Result { - if o.Options.recycleValidators && !o.Options.skipRedeemOnValidate { + if o.Options.recycleValidators { defer func() { o.redeem() }() @@ -343,7 +343,7 @@ func (o *objectValidator) validatePropertiesSchema(val map[string]interface{}, r // if a default value is defined, creates the property from defaults // NOTE: JSON schema does not enforce default values to be valid against schema. Swagger does. createdFromDefaults[pName] = struct{}{} - res.addPropertySchemata(val, pName, pSchema) // TODO(fred): issue there reusing a pointer + res.addPropertySchemata(val, pName, pSchema) // this shallow-clones the content of the pSchema pointer } } diff --git a/result.go b/result.go index 9ae464a..c711539 100644 --- a/result.go +++ b/result.go @@ -240,12 +240,14 @@ func (r *Result) addRootObjectSchemata(s *spec.Schema) { } // addPropertySchemata adds the given schemata for the object and field. -// The slice schemata might be reused. I.e. do not modify it after being added to a result. +// +// Since the slice schemata might be reused, it is shallow-cloned before saving it into the result. func (r *Result) addPropertySchemata(obj map[string]interface{}, fld string, schema *spec.Schema) { if r.fieldSchemata == nil { r.fieldSchemata = make([]fieldSchemata, 0, len(obj)) } - r.fieldSchemata = append(r.fieldSchemata, fieldSchemata{obj: obj, field: fld, schemata: schemata{one: schema}}) + clone := *schema + r.fieldSchemata = append(r.fieldSchemata, fieldSchemata{obj: obj, field: fld, schemata: schemata{one: &clone}}) } /* diff --git a/schema.go b/schema.go index 737d890..ca57e0a 100644 --- a/schema.go +++ b/schema.go @@ -39,7 +39,9 @@ type SchemaValidator struct { // // When no pre-parsed *spec.Schema structure is provided, it uses a JSON schema as default. See example. func AgainstSchema(schema *spec.Schema, data interface{}, formats strfmt.Registry, options ...Option) error { - res := NewSchemaValidator(schema, nil, "", formats, append(options, WithRecycleValidators(true))...).Validate(data) + res := NewSchemaValidator(schema, nil, "", formats, + append(options, WithRecycleValidators(true))..., + ).Validate(data) if res.HasErrors() { return errors.CompositeValidationError(res.Errors...) } @@ -50,7 +52,7 @@ func AgainstSchema(schema *spec.Schema, data interface{}, formats strfmt.Registr // // Panics if the provided schema is invalid. func NewSchemaValidator(schema *spec.Schema, rootSchema interface{}, root string, formats strfmt.Registry, options ...Option) *SchemaValidator { - opts := &SchemaValidatorOptions{} + opts := new(SchemaValidatorOptions) for _, o := range options { o(opts) } @@ -76,7 +78,7 @@ func newSchemaValidator(schema *spec.Schema, rootSchema interface{}, root string } if opts == nil { - opts = &SchemaValidatorOptions{} + opts = new(SchemaValidatorOptions) } var s *SchemaValidator @@ -132,7 +134,7 @@ func (s *SchemaValidator) Validate(data interface{}) *Result { result = &Result{data: data} } - if s.Options.recycleValidators && !s.Options.skipRedeemOnValidate { + if s.Options.recycleValidators { defer func() { s.redeem() // one-time use validator }() @@ -147,7 +149,7 @@ func (s *SchemaValidator) Validate(data interface{}) *Result { result.Merge(s.validators[0].Validate(data)) // type validator result.Merge(s.validators[6].Validate(data)) // common validator - if s.Options.recycleValidators && !s.Options.skipRedeemOnValidate { + if s.Options.recycleValidators { s.validators[0] = nil s.validators[6] = nil s.redeemChildren() @@ -200,7 +202,7 @@ func (s *SchemaValidator) Validate(data interface{}) *Result { for idx, v := range s.validators { if !v.Applies(s.Schema, kind) { - if s.Options.recycleValidators && !s.Options.skipRedeemOnValidate { + if s.Options.recycleValidators { // Validate won't be called, so relinquish this validator if redeemableChildren, ok := v.(interface{ redeemChildren() }); ok { redeemableChildren.redeemChildren() diff --git a/schema_option.go b/schema_option.go index deaece3..60d129f 100644 --- a/schema_option.go +++ b/schema_option.go @@ -19,7 +19,6 @@ type SchemaValidatorOptions struct { EnableObjectArrayTypeCheck bool EnableArrayMustHaveItemsCheck bool recycleValidators bool - skipRedeemOnValidate bool // internal use for slice validation recycleResult bool intern intern } @@ -57,32 +56,6 @@ func WithRecycleValidators(enable bool) Option { } } -func withSkipRedeemOnValidate(enable bool) Option { - return func(svo *SchemaValidatorOptions) { - svo.skipRedeemOnValidate = enable - } -} - -func withOptions(o SchemaValidatorOptions) Option { - return func(svo *SchemaValidatorOptions) { - *svo = o - } -} - -func withOptionsForceNoSkip(o SchemaValidatorOptions) Option { - return func(svo *SchemaValidatorOptions) { - *svo = o - svo.skipRedeemOnValidate = false - } -} - -func withOptionsForceSkip(o SchemaValidatorOptions) Option { - return func(svo *SchemaValidatorOptions) { - *svo = o - svo.skipRedeemOnValidate = true - } -} - func withRecycleResults(enable bool) Option { return func(svo *SchemaValidatorOptions) { svo.recycleResult = enable @@ -103,6 +76,5 @@ func (svo SchemaValidatorOptions) Options() []Option { EnableObjectArrayTypeCheck(svo.EnableObjectArrayTypeCheck), EnableArrayMustHaveItemsCheck(svo.EnableArrayMustHaveItemsCheck), WithRecycleValidators(svo.recycleValidators), - withSkipRedeemOnValidate(svo.skipRedeemOnValidate), } } diff --git a/schema_props.go b/schema_props.go index f0b31ce..0a7f7b8 100644 --- a/schema_props.go +++ b/schema_props.go @@ -47,7 +47,7 @@ func newSchemaPropsValidator( path string, in string, allOf, oneOf, anyOf []spec.Schema, not *spec.Schema, deps spec.Dependencies, root interface{}, formats strfmt.Registry, opts *SchemaValidatorOptions) *schemaPropsValidator { if opts == nil { - opts = &SchemaValidatorOptions{} + opts = new(SchemaValidatorOptions) } anyValidators := make([]*SchemaValidator, 0, len(anyOf)) @@ -113,7 +113,7 @@ func (s *schemaPropsValidator) Validate(data interface{}) *Result { keepResultOneOf := poolOfResults.BorrowResult() keepResultAllOf := poolOfResults.BorrowResult() - if s.Options.recycleValidators && !s.Options.skipRedeemOnValidate { + if s.Options.recycleValidators { defer func() { s.redeem() diff --git a/schema_props_test.go b/schema_props_test.go index e656a5d..d164ca7 100644 --- a/schema_props_test.go +++ b/schema_props_test.go @@ -17,6 +17,7 @@ package validate import ( "testing" + "github.com/go-openapi/strfmt" "github.com/stretchr/testify/assert" ) @@ -24,7 +25,8 @@ import ( // to simulate with specs // (this one is a trivial, just to check all methods are filled) func TestSchemaPropsValidator_EdgeCases(t *testing.T) { - s := schemaPropsValidator{} + s := newSchemaPropsValidator( + "", "", nil, nil, nil, nil, nil, nil, strfmt.Default, nil) s.SetPath("path") assert.Equal(t, "path", s.Path) } diff --git a/slice_validator.go b/slice_validator.go index ba0234a..e974d3e 100644 --- a/slice_validator.go +++ b/slice_validator.go @@ -40,7 +40,7 @@ func newSliceValidator(path, in string, additionalItems *spec.SchemaOrBool, items *spec.SchemaOrArray, root interface{}, formats strfmt.Registry, opts *SchemaValidatorOptions) *schemaSliceValidator { if opts == nil { - opts = &SchemaValidatorOptions{} + opts = new(SchemaValidatorOptions) } var v *schemaSliceValidator @@ -75,7 +75,7 @@ func (s *schemaSliceValidator) Applies(source interface{}, kind reflect.Kind) bo } func (s *schemaSliceValidator) Validate(data interface{}) *Result { - if s.Options.recycleValidators && !s.Options.skipRedeemOnValidate { + if s.Options.recycleValidators { defer func() { s.redeem() }() diff --git a/spec.go b/spec.go index d736630..3a47232 100644 --- a/spec.go +++ b/spec.go @@ -65,7 +65,7 @@ type SpecValidator struct { // NewSpecValidator creates a new swagger spec validator instance func NewSpecValidator(schema *spec.Schema, formats strfmt.Registry) *SpecValidator { // schema options that apply to all called validators - schemaOptions := &SchemaValidatorOptions{} + schemaOptions := new(SchemaValidatorOptions) for _, o := range []Option{ SwaggerSchema(true), WithRecycleValidators(true), diff --git a/type.go b/type.go index 64cc261..0f63d15 100644 --- a/type.go +++ b/type.go @@ -35,7 +35,7 @@ type typeValidator struct { func newTypeValidator(path, in string, typ spec.StringOrArray, nullable bool, format string, opts *SchemaValidatorOptions) *typeValidator { if opts == nil { - opts = &SchemaValidatorOptions{} + opts = new(SchemaValidatorOptions) } var t *typeValidator @@ -162,7 +162,7 @@ func (t *typeValidator) Applies(source interface{}, _ reflect.Kind) bool { } func (t *typeValidator) Validate(data interface{}) *Result { - if t.Options.recycleValidators && !t.Options.skipRedeemOnValidate { + if t.Options.recycleValidators { defer func() { t.redeem() }() diff --git a/type_test.go b/type_test.go index 41febbf..2715139 100644 --- a/type_test.go +++ b/type_test.go @@ -16,12 +16,14 @@ package validate import ( "io" + "reflect" "testing" "time" "github.com/go-openapi/strfmt" "github.com/go-openapi/swag" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) type expectedJSONType struct { @@ -263,7 +265,14 @@ func TestType_schemaInfoForType(t *testing.T) { */ } - v := &typeValidator{} + v := newTypeValidator( + "", "", nil, false, "", nil, + ) + + t.Run("should not apply", func(t *testing.T) { + require.False(t, v.Applies("x", reflect.Map)) + }) + for _, x := range testTypes { value := x.value diff --git a/validator.go b/validator.go index 0e3a383..5314e85 100644 --- a/validator.go +++ b/validator.go @@ -74,7 +74,7 @@ func newItemsValidator(path, in string, items *spec.Items, root interface{}, for } func (i *itemsValidator) Validate(index int, data interface{}) *Result { - if i.Options.recycleValidators && !i.Options.skipRedeemOnValidate { + if i.Options.recycleValidators { defer func() { i.redeemChildren() i.redeem() @@ -94,7 +94,7 @@ func (i *itemsValidator) Validate(index int, data interface{}) *Result { for idx, validator := range i.validators { if !validator.Applies(i.root, kind) { - if i.Options.recycleValidators && !i.Options.skipRedeemOnValidate { + if i.Options.recycleValidators { // Validate won't be called, so relinquish this validator if redeemableChildren, ok := validator.(interface{ redeemChildren() }); ok { redeemableChildren.redeemChildren() @@ -258,7 +258,7 @@ func (b *basicCommonValidator) Applies(source interface{}, _ reflect.Kind) bool } func (b *basicCommonValidator) Validate(data interface{}) (res *Result) { - if b.Options.recycleValidators && !b.Options.skipRedeemOnValidate { + if b.Options.recycleValidators { defer func() { b.redeem() }() @@ -345,6 +345,10 @@ func newHeaderValidator(name string, header *spec.Header, formats strfmt.Registr // Validate the value of the header against its schema func (p *HeaderValidator) Validate(data interface{}) *Result { + if data == nil { + return nil + } + var result *Result if p.Options.recycleResult { result = poolOfResults.BorrowResult() @@ -355,7 +359,7 @@ func (p *HeaderValidator) Validate(data interface{}) *Result { tpe := reflect.TypeOf(data) kind := tpe.Kind() - if p.Options.recycleValidators && !p.Options.skipRedeemOnValidate { + if p.Options.recycleValidators { defer func() { p.redeemChildren() p.redeem() @@ -364,7 +368,7 @@ func (p *HeaderValidator) Validate(data interface{}) *Result { for idx, validator := range p.validators { if !validator.Applies(p.header, kind) { - if p.Options.recycleValidators && !p.Options.skipRedeemOnValidate { + if p.Options.recycleValidators { // Validate won't be called, so relinquish this validator if redeemableChildren, ok := validator.(interface{ redeemChildren() }); ok { redeemableChildren.redeemChildren() @@ -526,16 +530,21 @@ func newParamValidator(param *spec.Parameter, formats strfmt.Registry, opts *Sch // Validate the data against the description of the parameter func (p *ParamValidator) Validate(data interface{}) *Result { + if data == nil { + return nil + } + var result *Result if p.Options.recycleResult { result = poolOfResults.BorrowResult() } else { result = new(Result) } + tpe := reflect.TypeOf(data) kind := tpe.Kind() - if p.Options.recycleValidators && !p.Options.skipRedeemOnValidate { + if p.Options.recycleValidators { defer func() { p.redeemChildren() p.redeem() @@ -545,7 +554,7 @@ func (p *ParamValidator) Validate(data interface{}) *Result { // TODO: validate type for idx, validator := range p.validators { if !validator.Applies(p.param, kind) { - if p.Options.recycleValidators && !p.Options.skipRedeemOnValidate { + if p.Options.recycleValidators { // Validate won't be called, so relinquish this validator if redeemableChildren, ok := validator.(interface{ redeemChildren() }); ok { redeemableChildren.redeemChildren() @@ -713,7 +722,7 @@ func (s *basicSliceValidator) Applies(source interface{}, kind reflect.Kind) boo } func (s *basicSliceValidator) Validate(data interface{}) *Result { - if s.Options.recycleValidators && !s.Options.skipRedeemOnValidate { + if s.Options.recycleValidators { defer func() { s.redeem() }() @@ -841,7 +850,7 @@ func (n *numberValidator) Applies(source interface{}, kind reflect.Kind) bool { // // TODO: default boundaries with MAX_SAFE_INTEGER are not checked (specific to json.Number?) func (n *numberValidator) Validate(val interface{}) *Result { - if n.Options.recycleValidators && !n.Options.skipRedeemOnValidate { + if n.Options.recycleValidators { defer func() { n.redeem() }() @@ -975,7 +984,7 @@ func (s *stringValidator) Applies(source interface{}, kind reflect.Kind) bool { } func (s *stringValidator) Validate(val interface{}) *Result { - if s.Options.recycleValidators && !s.Options.skipRedeemOnValidate { + if s.Options.recycleValidators { defer func() { s.redeem() }() diff --git a/validator_test.go b/validator_test.go index 1d9caff..dfe521d 100644 --- a/validator_test.go +++ b/validator_test.go @@ -20,28 +20,44 @@ import ( "testing" "github.com/go-openapi/spec" + "github.com/go-openapi/strfmt" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) +func TestHeaderValidator(t *testing.T) { + v := NewHeaderValidator("header", &spec.Header{}, strfmt.Default, SwaggerSchema(true)) + + res := v.Validate(nil) + require.Nil(t, res) +} + +func TestParamValidator(t *testing.T) { + v := NewParamValidator(&spec.Parameter{}, strfmt.Default, SwaggerSchema(true)) + + res := v.Validate(nil) + require.Nil(t, res) +} + func TestNumberValidator_EdgeCases(t *testing.T) { // Apply var min = float64(math.MinInt32 - 1) var max = float64(math.MaxInt32 + 1) - v := numberValidator{ - Path: "path", - In: "in", - //Default: - //MultipleOf: - Maximum: &max, // *float64 - ExclusiveMaximum: false, - Minimum: &min, // *float64 - ExclusiveMinimum: false, + v := newNumberValidator( + "path", + "in", + nil, + nil, + &max, // *float64 + false, + &min, // *float64 + false, // Allows for more accurate behavior regarding integers - Type: "integer", - Format: "int32", - Options: &SchemaValidatorOptions{}, - } + "integer", + "int32", + nil, + ) // numberValidator applies to: Parameter,Schema,Items,Header @@ -52,7 +68,7 @@ func TestNumberValidator_EdgeCases(t *testing.T) { new(spec.Header), } - testNumberApply(t, &v, sources) + testNumberApply(t, v, sources) assert.False(t, v.Applies(float64(32), reflect.Float64)) @@ -91,7 +107,9 @@ func testNumberApply(t *testing.T, v *numberValidator, sources []interface{}) { func TestStringValidator_EdgeCases(t *testing.T) { // Apply - v := stringValidator{} + v := newStringValidator( + "", "", nil, false, false, nil, nil, "", nil, + ) // stringValidator applies to: Parameter,Schema,Items,Header @@ -102,10 +120,9 @@ func TestStringValidator_EdgeCases(t *testing.T) { new(spec.Header), } - testStringApply(t, &v, sources) + testStringApply(t, v, sources) assert.False(t, v.Applies("A string", reflect.String)) - } func testStringApply(t *testing.T, v *stringValidator, sources []interface{}) { @@ -121,7 +138,10 @@ func testStringApply(t *testing.T, v *stringValidator, sources []interface{}) { func TestBasicCommonValidator_EdgeCases(t *testing.T) { // Apply - v := basicCommonValidator{} + v := newBasicCommonValidator( + "", "", + nil, []interface{}{"a", nil, 3}, nil, + ) // basicCommonValidator applies to: Parameter,Schema,Header @@ -131,10 +151,21 @@ func TestBasicCommonValidator_EdgeCases(t *testing.T) { new(spec.Header), } - testCommonApply(t, &v, sources) + testCommonApply(t, v, sources) assert.False(t, v.Applies("A string", reflect.String)) + t.Run("shoud validate Enum", func(t *testing.T) { + res := v.Validate("a") + require.Nil(t, res) + + res = v.Validate(3) + require.Nil(t, res) + + res = v.Validate("b") + require.NotNil(t, res) + assert.True(t, res.HasErrors()) + }) } func testCommonApply(t *testing.T, v *basicCommonValidator, sources []interface{}) { @@ -146,7 +177,10 @@ func testCommonApply(t *testing.T, v *basicCommonValidator, sources []interface{ func TestBasicSliceValidator_EdgeCases(t *testing.T) { // Apply - v := basicSliceValidator{} + v := newBasicSliceValidator( + "", "", + nil, nil, nil, false, nil, nil, strfmt.Default, nil, + ) // basicCommonValidator applies to: Parameter,Schema,Header @@ -156,11 +190,10 @@ func TestBasicSliceValidator_EdgeCases(t *testing.T) { new(spec.Header), } - testSliceApply(t, &v, sources) + testSliceApply(t, v, sources) assert.False(t, v.Applies(new(spec.Schema), reflect.Slice)) assert.False(t, v.Applies(new(spec.Parameter), reflect.String)) - } func testSliceApply(t *testing.T, v *basicSliceValidator, sources []interface{}) {