summaryrefslogtreecommitdiff
path: root/vendor/github.com/go-openapi/validate/values.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/go-openapi/validate/values.go')
-rw-r--r--vendor/github.com/go-openapi/validate/values.go450
1 files changed, 450 insertions, 0 deletions
diff --git a/vendor/github.com/go-openapi/validate/values.go b/vendor/github.com/go-openapi/validate/values.go
new file mode 100644
index 000000000..e7ad8c103
--- /dev/null
+++ b/vendor/github.com/go-openapi/validate/values.go
@@ -0,0 +1,450 @@
+// Copyright 2015 go-swagger maintainers
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package validate
+
+import (
+ "context"
+ "fmt"
+ "reflect"
+ "strings"
+ "unicode/utf8"
+
+ "github.com/go-openapi/errors"
+ "github.com/go-openapi/strfmt"
+ "github.com/go-openapi/swag"
+)
+
+// Enum validates if the data is a member of the enum
+func Enum(path, in string, data interface{}, enum interface{}) *errors.Validation {
+ return EnumCase(path, in, data, enum, true)
+}
+
+// EnumCase validates if the data is a member of the enum and may respect case-sensitivity for strings
+func EnumCase(path, in string, data interface{}, enum interface{}, caseSensitive bool) *errors.Validation {
+ val := reflect.ValueOf(enum)
+ if val.Kind() != reflect.Slice {
+ return nil
+ }
+
+ dataString := convertEnumCaseStringKind(data, caseSensitive)
+ var values []interface{}
+ for i := 0; i < val.Len(); i++ {
+ ele := val.Index(i)
+ enumValue := ele.Interface()
+ if data != nil {
+ if reflect.DeepEqual(data, enumValue) {
+ return nil
+ }
+ enumString := convertEnumCaseStringKind(enumValue, caseSensitive)
+ if dataString != nil && enumString != nil && strings.EqualFold(*dataString, *enumString) {
+ return nil
+ }
+ actualType := reflect.TypeOf(enumValue)
+ if actualType == nil { // Safeguard. Frankly, I don't know how we may get a nil
+ continue
+ }
+ expectedValue := reflect.ValueOf(data)
+ if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) {
+ // Attempt comparison after type conversion
+ if reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), enumValue) {
+ return nil
+ }
+ }
+ }
+ values = append(values, enumValue)
+ }
+ return errors.EnumFail(path, in, data, values)
+}
+
+// convertEnumCaseStringKind converts interface if it is kind of string and case insensitivity is set
+func convertEnumCaseStringKind(value interface{}, caseSensitive bool) *string {
+ if caseSensitive {
+ return nil
+ }
+
+ val := reflect.ValueOf(value)
+ if val.Kind() != reflect.String {
+ return nil
+ }
+
+ str := fmt.Sprintf("%v", value)
+ return &str
+}
+
+// MinItems validates that there are at least n items in a slice
+func MinItems(path, in string, size, min int64) *errors.Validation {
+ if size < min {
+ return errors.TooFewItems(path, in, min, size)
+ }
+ return nil
+}
+
+// MaxItems validates that there are at most n items in a slice
+func MaxItems(path, in string, size, max int64) *errors.Validation {
+ if size > max {
+ return errors.TooManyItems(path, in, max, size)
+ }
+ return nil
+}
+
+// UniqueItems validates that the provided slice has unique elements
+func UniqueItems(path, in string, data interface{}) *errors.Validation {
+ val := reflect.ValueOf(data)
+ if val.Kind() != reflect.Slice {
+ return nil
+ }
+ var unique []interface{}
+ for i := 0; i < val.Len(); i++ {
+ v := val.Index(i).Interface()
+ for _, u := range unique {
+ if reflect.DeepEqual(v, u) {
+ return errors.DuplicateItems(path, in)
+ }
+ }
+ unique = append(unique, v)
+ }
+ return nil
+}
+
+// MinLength validates a string for minimum length
+func MinLength(path, in, data string, minLength int64) *errors.Validation {
+ strLen := int64(utf8.RuneCount([]byte(data)))
+ if strLen < minLength {
+ return errors.TooShort(path, in, minLength, data)
+ }
+ return nil
+}
+
+// MaxLength validates a string for maximum length
+func MaxLength(path, in, data string, maxLength int64) *errors.Validation {
+ strLen := int64(utf8.RuneCount([]byte(data)))
+ if strLen > maxLength {
+ return errors.TooLong(path, in, maxLength, data)
+ }
+ return nil
+}
+
+// ReadOnly validates an interface for readonly
+func ReadOnly(ctx context.Context, path, in string, data interface{}) *errors.Validation {
+
+ // read only is only validated when operationType is request
+ if op := extractOperationType(ctx); op != request {
+ return nil
+ }
+
+ // data must be of zero value of its type
+ val := reflect.ValueOf(data)
+ if val.IsValid() {
+ if reflect.DeepEqual(reflect.Zero(val.Type()).Interface(), val.Interface()) {
+ return nil
+ }
+ } else {
+ return nil
+ }
+
+ return errors.ReadOnly(path, in, data)
+}
+
+// Required validates an interface for requiredness
+func Required(path, in string, data interface{}) *errors.Validation {
+ val := reflect.ValueOf(data)
+ if val.IsValid() {
+ if reflect.DeepEqual(reflect.Zero(val.Type()).Interface(), val.Interface()) {
+ return errors.Required(path, in, data)
+ }
+ return nil
+ }
+ return errors.Required(path, in, data)
+}
+
+// RequiredString validates a string for requiredness
+func RequiredString(path, in, data string) *errors.Validation {
+ if data == "" {
+ return errors.Required(path, in, data)
+ }
+ return nil
+}
+
+// RequiredNumber validates a number for requiredness
+func RequiredNumber(path, in string, data float64) *errors.Validation {
+ if data == 0 {
+ return errors.Required(path, in, data)
+ }
+ return nil
+}
+
+// Pattern validates a string against a regular expression
+func Pattern(path, in, data, pattern string) *errors.Validation {
+ re, err := compileRegexp(pattern)
+ if err != nil {
+ return errors.FailedPattern(path, in, fmt.Sprintf("%s, but pattern is invalid: %s", pattern, err.Error()), data)
+ }
+ if !re.MatchString(data) {
+ return errors.FailedPattern(path, in, pattern, data)
+ }
+ return nil
+}
+
+// MaximumInt validates if a number is smaller than a given maximum
+func MaximumInt(path, in string, data, max int64, exclusive bool) *errors.Validation {
+ if (!exclusive && data > max) || (exclusive && data >= max) {
+ return errors.ExceedsMaximumInt(path, in, max, exclusive, data)
+ }
+ return nil
+}
+
+// MaximumUint validates if a number is smaller than a given maximum
+func MaximumUint(path, in string, data, max uint64, exclusive bool) *errors.Validation {
+ if (!exclusive && data > max) || (exclusive && data >= max) {
+ return errors.ExceedsMaximumUint(path, in, max, exclusive, data)
+ }
+ return nil
+}
+
+// Maximum validates if a number is smaller than a given maximum
+func Maximum(path, in string, data, max float64, exclusive bool) *errors.Validation {
+ if (!exclusive && data > max) || (exclusive && data >= max) {
+ return errors.ExceedsMaximum(path, in, max, exclusive, data)
+ }
+ return nil
+}
+
+// Minimum validates if a number is smaller than a given minimum
+func Minimum(path, in string, data, min float64, exclusive bool) *errors.Validation {
+ if (!exclusive && data < min) || (exclusive && data <= min) {
+ return errors.ExceedsMinimum(path, in, min, exclusive, data)
+ }
+ return nil
+}
+
+// MinimumInt validates if a number is smaller than a given minimum
+func MinimumInt(path, in string, data, min int64, exclusive bool) *errors.Validation {
+ if (!exclusive && data < min) || (exclusive && data <= min) {
+ return errors.ExceedsMinimumInt(path, in, min, exclusive, data)
+ }
+ return nil
+}
+
+// MinimumUint validates if a number is smaller than a given minimum
+func MinimumUint(path, in string, data, min uint64, exclusive bool) *errors.Validation {
+ if (!exclusive && data < min) || (exclusive && data <= min) {
+ return errors.ExceedsMinimumUint(path, in, min, exclusive, data)
+ }
+ return nil
+}
+
+// MultipleOf validates if the provided number is a multiple of the factor
+func MultipleOf(path, in string, data, factor float64) *errors.Validation {
+ // multipleOf factor must be positive
+ if factor <= 0 {
+ return errors.MultipleOfMustBePositive(path, in, factor)
+ }
+ var mult float64
+ if factor < 1 {
+ mult = 1 / factor * data
+ } else {
+ mult = data / factor
+ }
+ if !swag.IsFloat64AJSONInteger(mult) {
+ return errors.NotMultipleOf(path, in, factor, data)
+ }
+ return nil
+}
+
+// MultipleOfInt validates if the provided integer is a multiple of the factor
+func MultipleOfInt(path, in string, data int64, factor int64) *errors.Validation {
+ // multipleOf factor must be positive
+ if factor <= 0 {
+ return errors.MultipleOfMustBePositive(path, in, factor)
+ }
+ mult := data / factor
+ if mult*factor != data {
+ return errors.NotMultipleOf(path, in, factor, data)
+ }
+ return nil
+}
+
+// MultipleOfUint validates if the provided unsigned integer is a multiple of the factor
+func MultipleOfUint(path, in string, data, factor uint64) *errors.Validation {
+ // multipleOf factor must be positive
+ if factor == 0 {
+ return errors.MultipleOfMustBePositive(path, in, factor)
+ }
+ mult := data / factor
+ if mult*factor != data {
+ return errors.NotMultipleOf(path, in, factor, data)
+ }
+ return nil
+}
+
+// FormatOf validates if a string matches a format in the format registry
+func FormatOf(path, in, format, data string, registry strfmt.Registry) *errors.Validation {
+ if registry == nil {
+ registry = strfmt.Default
+ }
+ if ok := registry.ContainsName(format); !ok {
+ return errors.InvalidTypeName(format)
+ }
+ if ok := registry.Validates(format, data); !ok {
+ return errors.InvalidType(path, in, format, data)
+ }
+ return nil
+}
+
+// MaximumNativeType provides native type constraint validation as a facade
+// to various numeric types versions of Maximum constraint check.
+//
+// Assumes that any possible loss conversion during conversion has been
+// checked beforehand.
+//
+// NOTE: currently, the max value is marshalled as a float64, no matter what,
+// which means there may be a loss during conversions (e.g. for very large integers)
+//
+// TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free
+func MaximumNativeType(path, in string, val interface{}, max float64, exclusive bool) *errors.Validation {
+ kind := reflect.ValueOf(val).Type().Kind()
+ switch kind {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ value := valueHelp.asInt64(val)
+ return MaximumInt(path, in, value, int64(max), exclusive)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ value := valueHelp.asUint64(val)
+ if max < 0 {
+ return errors.ExceedsMaximum(path, in, max, exclusive, val)
+ }
+ return MaximumUint(path, in, value, uint64(max), exclusive)
+ case reflect.Float32, reflect.Float64:
+ fallthrough
+ default:
+ value := valueHelp.asFloat64(val)
+ return Maximum(path, in, value, max, exclusive)
+ }
+}
+
+// MinimumNativeType provides native type constraint validation as a facade
+// to various numeric types versions of Minimum constraint check.
+//
+// Assumes that any possible loss conversion during conversion has been
+// checked beforehand.
+//
+// NOTE: currently, the min value is marshalled as a float64, no matter what,
+// which means there may be a loss during conversions (e.g. for very large integers)
+//
+// TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free
+func MinimumNativeType(path, in string, val interface{}, min float64, exclusive bool) *errors.Validation {
+ kind := reflect.ValueOf(val).Type().Kind()
+ switch kind {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ value := valueHelp.asInt64(val)
+ return MinimumInt(path, in, value, int64(min), exclusive)
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ value := valueHelp.asUint64(val)
+ if min < 0 {
+ return nil
+ }
+ return MinimumUint(path, in, value, uint64(min), exclusive)
+ case reflect.Float32, reflect.Float64:
+ fallthrough
+ default:
+ value := valueHelp.asFloat64(val)
+ return Minimum(path, in, value, min, exclusive)
+ }
+}
+
+// MultipleOfNativeType provides native type constraint validation as a facade
+// to various numeric types version of MultipleOf constraint check.
+//
+// Assumes that any possible loss conversion during conversion has been
+// checked beforehand.
+//
+// NOTE: currently, the multipleOf factor is marshalled as a float64, no matter what,
+// which means there may be a loss during conversions (e.g. for very large integers)
+//
+// TODO: Normally, a JSON MAX_SAFE_INTEGER check would ensure conversion remains loss-free
+func MultipleOfNativeType(path, in string, val interface{}, multipleOf float64) *errors.Validation {
+ kind := reflect.ValueOf(val).Type().Kind()
+ switch kind {
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ value := valueHelp.asInt64(val)
+ return MultipleOfInt(path, in, value, int64(multipleOf))
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ value := valueHelp.asUint64(val)
+ return MultipleOfUint(path, in, value, uint64(multipleOf))
+ case reflect.Float32, reflect.Float64:
+ fallthrough
+ default:
+ value := valueHelp.asFloat64(val)
+ return MultipleOf(path, in, value, multipleOf)
+ }
+}
+
+// IsValueValidAgainstRange checks that a numeric value is compatible with
+// the range defined by Type and Format, that is, may be converted without loss.
+//
+// NOTE: this check is about type capacity and not formal verification such as: 1.0 != 1L
+func IsValueValidAgainstRange(val interface{}, typeName, format, prefix, path string) error {
+ kind := reflect.ValueOf(val).Type().Kind()
+
+ // What is the string representation of val
+ var stringRep string
+ switch kind {
+ case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
+ stringRep = swag.FormatUint64(valueHelp.asUint64(val))
+ case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
+ stringRep = swag.FormatInt64(valueHelp.asInt64(val))
+ case reflect.Float32, reflect.Float64:
+ stringRep = swag.FormatFloat64(valueHelp.asFloat64(val))
+ default:
+ return fmt.Errorf("%s value number range checking called with invalid (non numeric) val type in %s", prefix, path)
+ }
+
+ var errVal error
+
+ switch typeName {
+ case integerType:
+ switch format {
+ case integerFormatInt32:
+ _, errVal = swag.ConvertInt32(stringRep)
+ case integerFormatUInt32:
+ _, errVal = swag.ConvertUint32(stringRep)
+ case integerFormatUInt64:
+ _, errVal = swag.ConvertUint64(stringRep)
+ case integerFormatInt64:
+ fallthrough
+ default:
+ _, errVal = swag.ConvertInt64(stringRep)
+ }
+ case numberType:
+ fallthrough
+ default:
+ switch format {
+ case numberFormatFloat, numberFormatFloat32:
+ _, errVal = swag.ConvertFloat32(stringRep)
+ case numberFormatDouble, numberFormatFloat64:
+ fallthrough
+ default:
+ // No check can be performed here since
+ // no number beyond float64 is supported
+ }
+ }
+ if errVal != nil { // We don't report the actual errVal from strconv
+ if format != "" {
+ errVal = fmt.Errorf("%s value must be of type %s with format %s in %s", prefix, typeName, format, path)
+ } else {
+ errVal = fmt.Errorf("%s value must be of type %s (default format) in %s", prefix, typeName, path)
+ }
+ }
+ return errVal
+}