diff --git a/keywords_numeric.go b/keywords_numeric.go index 243b6ef..eb71ec6 100644 --- a/keywords_numeric.go +++ b/keywords_numeric.go @@ -26,10 +26,10 @@ func (m *MultipleOf) Resolve(pointer jptr.Pointer, uri string) *Schema { // ValidateKeyword implements the Keyword interface for MultipleOf func (m MultipleOf) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) { schemaDebug("[MultipleOf] Validating") - if num, ok := data.(float64); ok { + if num, ok := convertNumberToFloat(data); ok { div := num / float64(m) if float64(int(div)) != div { - currentState.AddError(data, fmt.Sprintf("must be a multiple of %f", m)) + currentState.AddError(data, fmt.Sprintf("must be a multiple of %v", m)) } } } @@ -53,9 +53,9 @@ func (m *Maximum) Resolve(pointer jptr.Pointer, uri string) *Schema { // ValidateKeyword implements the Keyword interface for Maximum func (m Maximum) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) { schemaDebug("[Maximum] Validating") - if num, ok := data.(float64); ok { + if num, ok := convertNumberToFloat(data); ok { if num > float64(m) { - currentState.AddError(data, fmt.Sprintf("must be less than or equal to %f", m)) + currentState.AddError(data, fmt.Sprintf("must be less than or equal to %v", m)) } } } @@ -79,9 +79,9 @@ func (m *ExclusiveMaximum) Resolve(pointer jptr.Pointer, uri string) *Schema { // ValidateKeyword implements the Keyword interface for ExclusiveMaximum func (m ExclusiveMaximum) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) { schemaDebug("[ExclusiveMaximum] Validating") - if num, ok := data.(float64); ok { + if num, ok := convertNumberToFloat(data); ok { if num >= float64(m) { - currentState.AddError(data, fmt.Sprintf("%f must be less than %f", num, m)) + currentState.AddError(data, fmt.Sprintf("%v must be less than %v", num, m)) } } } @@ -105,9 +105,9 @@ func (m *Minimum) Resolve(pointer jptr.Pointer, uri string) *Schema { // ValidateKeyword implements the Keyword interface for Minimum func (m Minimum) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) { schemaDebug("[Minimum] Validating") - if num, ok := data.(float64); ok { + if num, ok := convertNumberToFloat(data); ok { if num < float64(m) { - currentState.AddError(data, fmt.Sprintf("must be less than or equal to %f", m)) + currentState.AddError(data, fmt.Sprintf("must be less than or equal to %v", m)) } } } @@ -131,9 +131,42 @@ func (m *ExclusiveMinimum) Resolve(pointer jptr.Pointer, uri string) *Schema { // ValidateKeyword implements the Keyword interface for ExclusiveMinimum func (m ExclusiveMinimum) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) { schemaDebug("[ExclusiveMinimum] Validating") - if num, ok := data.(float64); ok { + if num, ok := convertNumberToFloat(data); ok { if num <= float64(m) { - currentState.AddError(data, fmt.Sprintf("%f must be less than %f", num, m)) + currentState.AddError(data, fmt.Sprintf("%v must be less than %v", num, m)) } } } + +func convertNumberToFloat(data interface{}) (float64, bool) { + switch v := data.(type) { + case uint: + return float64(v), true + case uint8: + return float64(v), true + case uint16: + return float64(v), true + case uint32: + return float64(v), true + case uint64: + return float64(v), true + case int: + return float64(v), true + case int8: + return float64(v), true + case int16: + return float64(v), true + case int32: + return float64(v), true + case int64: + return float64(v), true + case float32: + return float64(v), true + case float64: + return float64(v), true + case uintptr: + return float64(v), true + } + + return 0, false +} diff --git a/keywords_standard.go b/keywords_standard.go index 56e5dd9..271c8b7 100644 --- a/keywords_standard.go +++ b/keywords_standard.go @@ -145,7 +145,11 @@ func DataType(data interface{}) string { switch reflect.TypeOf(data).Kind() { case reflect.Bool: return "boolean" - case reflect.Float64: + + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uintptr: + return "integer" + case reflect.Float32, reflect.Float64: number := reflect.ValueOf(data).Float() if float64(int(number)) == number { return "integer" diff --git a/schema_test.go b/schema_test.go index c5dc5d5..1c30604 100644 --- a/schema_test.go +++ b/schema_test.go @@ -579,7 +579,17 @@ func TestDataType(t *testing.T) { {map[string]interface{}{}, "object"}, {struct{}{}, "object"}, {customObject{}, "object"}, - {int8(42), "unknown"}, + {uint8(42), "integer"}, + {uint16(42), "integer"}, + {uint32(42), "integer"}, + {uint64(42), "integer"}, + {int8(42), "integer"}, + {int16(42), "integer"}, + {int32(42), "integer"}, + {int64(42), "integer"}, + {float32(42), "integer"}, + {float32(42.0), "integer"}, + {float32(42.5), "number"}, // special cases which should pass with type hints {"true", "boolean"}, {4.0, "number"},