fix: Schema.Minimum and Schema.Maxmium are now float64

This commit is contained in:
Derrick J. Wippler
2023-05-30 11:42:41 -05:00
committed by quobix
parent 06f6b243a8
commit a09916eb67
8 changed files with 90 additions and 42 deletions

3
.gitignore vendored
View File

@@ -1 +1,2 @@
test-operation.yaml test-operation.yaml
.idea/

View File

@@ -26,12 +26,12 @@ type Schema struct {
SchemaTypeRef string `json:"$schema,omitempty" yaml:"$schema,omitempty"` SchemaTypeRef string `json:"$schema,omitempty" yaml:"$schema,omitempty"`
// In versions 2 and 3.0, this ExclusiveMaximum can only be a boolean. // In versions 2 and 3.0, this ExclusiveMaximum can only be a boolean.
// In version 3.1, ExclusiveMaximum is an integer. // In version 3.1, ExclusiveMaximum is a number.
ExclusiveMaximum *DynamicValue[bool, int64] `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"` ExclusiveMaximum *DynamicValue[bool, float64] `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"`
// In versions 2 and 3.0, this ExclusiveMinimum can only be a boolean. // In versions 2 and 3.0, this ExclusiveMinimum can only be a boolean.
// In version 3.1, ExclusiveMinimum is an integer. // In version 3.1, ExclusiveMinimum is a number.
ExclusiveMinimum *DynamicValue[bool, int64] `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"` ExclusiveMinimum *DynamicValue[bool, float64] `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"`
// In versions 2 and 3.0, this Type is a single value, so array will only ever have one value // In versions 2 and 3.0, this Type is a single value, so array will only ever have one value
// in version 3.1, Type can be multiple values // in version 3.1, Type can be multiple values
@@ -74,9 +74,9 @@ type Schema struct {
Not *SchemaProxy `json:"not,omitempty" yaml:"not,omitempty"` Not *SchemaProxy `json:"not,omitempty" yaml:"not,omitempty"`
Properties map[string]*SchemaProxy `json:"properties,omitempty" yaml:"properties,omitempty"` Properties map[string]*SchemaProxy `json:"properties,omitempty" yaml:"properties,omitempty"`
Title string `json:"title,omitempty" yaml:"title,omitempty"` Title string `json:"title,omitempty" yaml:"title,omitempty"`
MultipleOf *int64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"` MultipleOf *float64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"`
Maximum *int64 `json:"maximum,omitempty" yaml:"maximum,omitempty"` Maximum *float64 `json:"maximum,omitempty" yaml:"maximum,omitempty"`
Minimum *int64 `json:"minimum,omitempty" yaml:"minimum,omitempty"` Minimum *float64 `json:"minimum,omitempty" yaml:"minimum,omitempty"`
MaxLength *int64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"` MaxLength *int64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"`
MinLength *int64 `json:"minLength,omitempty" yaml:"minLength,omitempty"` MinLength *int64 `json:"minLength,omitempty" yaml:"minLength,omitempty"`
Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"` Pattern string `json:"pattern,omitempty" yaml:"pattern,omitempty"`
@@ -121,26 +121,26 @@ func NewSchema(schema *base.Schema) *Schema {
} }
// if we're dealing with a 3.0 spec using a bool // if we're dealing with a 3.0 spec using a bool
if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsA() { if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsA() {
s.ExclusiveMaximum = &DynamicValue[bool, int64]{ s.ExclusiveMaximum = &DynamicValue[bool, float64]{
A: schema.ExclusiveMaximum.Value.A, A: schema.ExclusiveMaximum.Value.A,
} }
} }
// if we're dealing with a 3.1 spec using an int // if we're dealing with a 3.1 spec using an int
if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsB() { if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsB() {
s.ExclusiveMaximum = &DynamicValue[bool, int64]{ s.ExclusiveMaximum = &DynamicValue[bool, float64]{
N: 1, N: 1,
B: schema.ExclusiveMaximum.Value.B, B: schema.ExclusiveMaximum.Value.B,
} }
} }
// if we're dealing with a 3.0 spec using a bool // if we're dealing with a 3.0 spec using a bool
if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsA() { if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsA() {
s.ExclusiveMinimum = &DynamicValue[bool, int64]{ s.ExclusiveMinimum = &DynamicValue[bool, float64]{
A: schema.ExclusiveMinimum.Value.A, A: schema.ExclusiveMinimum.Value.A,
} }
} }
// if we're dealing with a 3.1 spec, using an int // if we're dealing with a 3.1 spec, using an int
if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsB() { if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsB() {
s.ExclusiveMinimum = &DynamicValue[bool, int64]{ s.ExclusiveMinimum = &DynamicValue[bool, float64]{
N: 1, N: 1,
B: schema.ExclusiveMinimum.Value.B, B: schema.ExclusiveMinimum.Value.B,
} }

View File

@@ -500,8 +500,8 @@ required: [cake, fish]`
assert.Nil(t, schemaProxy.GetBuildError()) assert.Nil(t, schemaProxy.GetBuildError())
assert.True(t, compiled.ExclusiveMaximum.A) assert.True(t, compiled.ExclusiveMaximum.A)
assert.Equal(t, int64(123), compiled.Properties["somethingB"].Schema().ExclusiveMinimum.B) assert.Equal(t, float64(123), compiled.Properties["somethingB"].Schema().ExclusiveMinimum.B)
assert.Equal(t, int64(334), compiled.Properties["somethingB"].Schema().ExclusiveMaximum.B) assert.Equal(t, float64(334), compiled.Properties["somethingB"].Schema().ExclusiveMaximum.B)
assert.Len(t, compiled.Properties["somethingB"].Schema().Properties["somethingBProp"].Schema().Type, 2) assert.Len(t, compiled.Properties["somethingB"].Schema().Properties["somethingBProp"].Schema().Type, 2)
assert.Equal(t, "nice", compiled.AdditionalProperties.(*SchemaProxy).Schema().Description) assert.Equal(t, "nice", compiled.AdditionalProperties.(*SchemaProxy).Schema().Description)
@@ -515,7 +515,7 @@ required: [cake, fish]`
} }
func TestSchemaProxy_GoLow(t *testing.T) { func TestSchemaProxy_GoLow(t *testing.T) {
const ymlComponents = `components: const ymlComponents = `components:
schemas: schemas:
rice: rice:
type: string type: string
@@ -586,25 +586,47 @@ type: number
assert.Nil(t, highSchema.ExclusiveMaximum) assert.Nil(t, highSchema.ExclusiveMaximum)
} }
func TestSchemaNumberMultipleOf(t *testing.T) { func TestSchemaNumberMultipleOfInt(t *testing.T) {
yml := ` yml := `
type: number type: number
multipleOf: 5 multipleOf: 5
` `
highSchema := getHighSchema(t, yml) highSchema := getHighSchema(t, yml)
value := int64(5) value := float64(5)
assert.EqualValues(t, &value, highSchema.MultipleOf) assert.EqualValues(t, &value, highSchema.MultipleOf)
} }
func TestSchemaNumberMinimum(t *testing.T) { func TestSchemaNumberMultipleOfFloat(t *testing.T) {
yml := `
type: number
multipleOf: 0.5
`
highSchema := getHighSchema(t, yml)
value := 0.5
assert.EqualValues(t, &value, highSchema.MultipleOf)
}
func TestSchemaNumberMinimumInt(t *testing.T) {
yml := ` yml := `
type: number type: number
minimum: 5 minimum: 5
` `
highSchema := getHighSchema(t, yml) highSchema := getHighSchema(t, yml)
value := int64(5) value := float64(5)
assert.EqualValues(t, &value, highSchema.Minimum)
}
func TestSchemaNumberMinimumFloat(t *testing.T) {
yml := `
type: number
minimum: 0.5
`
highSchema := getHighSchema(t, yml)
value := 0.5
assert.EqualValues(t, &value, highSchema.Minimum) assert.EqualValues(t, &value, highSchema.Minimum)
} }
@@ -615,7 +637,7 @@ minimum: 0
` `
highSchema := getHighSchema(t, yml) highSchema := getHighSchema(t, yml)
value := int64(0) value := float64(0)
assert.EqualValues(t, &value, highSchema.Minimum) assert.EqualValues(t, &value, highSchema.Minimum)
} }
@@ -638,7 +660,7 @@ maximum: 5
` `
highSchema := getHighSchema(t, yml) highSchema := getHighSchema(t, yml)
value := int64(5) value := float64(5)
assert.EqualValues(t, &value, highSchema.Maximum) assert.EqualValues(t, &value, highSchema.Maximum)
} }
@@ -649,7 +671,7 @@ maximum: 0
` `
highSchema := getHighSchema(t, yml) highSchema := getHighSchema(t, yml)
value := int64(0) value := float64(0)
assert.EqualValues(t, &value, highSchema.Maximum) assert.EqualValues(t, &value, highSchema.Maximum)
} }

View File

@@ -52,10 +52,10 @@ type Schema struct {
SchemaTypeRef low.NodeReference[string] SchemaTypeRef low.NodeReference[string]
// In versions 2 and 3.0, this ExclusiveMaximum can only be a boolean. // In versions 2 and 3.0, this ExclusiveMaximum can only be a boolean.
ExclusiveMaximum low.NodeReference[*SchemaDynamicValue[bool, int64]] ExclusiveMaximum low.NodeReference[*SchemaDynamicValue[bool, float64]]
// In versions 2 and 3.0, this ExclusiveMinimum can only be a boolean. // In versions 2 and 3.0, this ExclusiveMinimum can only be a boolean.
ExclusiveMinimum low.NodeReference[*SchemaDynamicValue[bool, int64]] ExclusiveMinimum low.NodeReference[*SchemaDynamicValue[bool, float64]]
// In versions 2 and 3.0, this Type is a single value, so array will only ever have one value // In versions 2 and 3.0, this Type is a single value, so array will only ever have one value
// in version 3.1, Type can be multiple values // in version 3.1, Type can be multiple values
@@ -94,9 +94,9 @@ type Schema struct {
// Compatible with all versions // Compatible with all versions
Title low.NodeReference[string] Title low.NodeReference[string]
MultipleOf low.NodeReference[int64] MultipleOf low.NodeReference[float64]
Maximum low.NodeReference[int64] Maximum low.NodeReference[float64]
Minimum low.NodeReference[int64] Minimum low.NodeReference[float64]
MaxLength low.NodeReference[int64] MaxLength low.NodeReference[int64]
MinLength low.NodeReference[int64] MinLength low.NodeReference[int64]
Pattern low.NodeReference[string] Pattern low.NodeReference[string]
@@ -575,18 +575,18 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
if exMinValue != nil { if exMinValue != nil {
if utils.IsNodeBoolValue(exMinValue) { if utils.IsNodeBoolValue(exMinValue) {
val, _ := strconv.ParseBool(exMinValue.Value) val, _ := strconv.ParseBool(exMinValue.Value)
s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, float64]]{
KeyNode: exMinLabel, KeyNode: exMinLabel,
ValueNode: exMinValue, ValueNode: exMinValue,
Value: &SchemaDynamicValue[bool, int64]{N: 0, A: val}, Value: &SchemaDynamicValue[bool, float64]{N: 0, A: val},
} }
} }
if utils.IsNodeIntValue(exMinValue) { if utils.IsNodeIntValue(exMinValue) {
val, _ := strconv.ParseInt(exMinValue.Value, 10, 64) val, _ := strconv.ParseFloat(exMinValue.Value, 64)
s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, float64]]{
KeyNode: exMinLabel, KeyNode: exMinLabel,
ValueNode: exMinValue, ValueNode: exMinValue,
Value: &SchemaDynamicValue[bool, int64]{N: 1, B: val}, Value: &SchemaDynamicValue[bool, float64]{N: 1, B: val},
} }
} }
} }
@@ -596,18 +596,18 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error {
if exMaxValue != nil { if exMaxValue != nil {
if utils.IsNodeBoolValue(exMaxValue) { if utils.IsNodeBoolValue(exMaxValue) {
val, _ := strconv.ParseBool(exMaxValue.Value) val, _ := strconv.ParseBool(exMaxValue.Value)
s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, float64]]{
KeyNode: exMaxLabel, KeyNode: exMaxLabel,
ValueNode: exMaxValue, ValueNode: exMaxValue,
Value: &SchemaDynamicValue[bool, int64]{N: 0, A: val}, Value: &SchemaDynamicValue[bool, float64]{N: 0, A: val},
} }
} }
if utils.IsNodeIntValue(exMaxValue) { if utils.IsNodeIntValue(exMaxValue) {
val, _ := strconv.ParseInt(exMaxValue.Value, 10, 64) val, _ := strconv.ParseFloat(exMaxValue.Value, 64)
s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, float64]]{
KeyNode: exMaxLabel, KeyNode: exMaxLabel,
ValueNode: exMaxValue, ValueNode: exMaxValue,
Value: &SchemaDynamicValue[bool, int64]{N: 1, B: val}, Value: &SchemaDynamicValue[bool, float64]{N: 1, B: val},
} }
} }
} }

View File

@@ -424,8 +424,8 @@ examples:
assert.True(t, sch.ExclusiveMinimum.Value.IsB()) assert.True(t, sch.ExclusiveMinimum.Value.IsB())
assert.False(t, sch.ExclusiveMinimum.Value.IsA()) assert.False(t, sch.ExclusiveMinimum.Value.IsA())
assert.True(t, sch.ExclusiveMaximum.Value.IsB()) assert.True(t, sch.ExclusiveMaximum.Value.IsB())
assert.Equal(t, int64(12), sch.ExclusiveMinimum.Value.B) assert.Equal(t, float64(12), sch.ExclusiveMinimum.Value.B)
assert.Equal(t, int64(13), sch.ExclusiveMaximum.Value.B) assert.Equal(t, float64(13), sch.ExclusiveMaximum.Value.B)
assert.Len(t, sch.Examples.Value, 1) assert.Len(t, sch.Examples.Value, 1)
assert.Equal(t, "testing", sch.Examples.Value[0].Value) assert.Equal(t, "testing", sch.Examples.Value[0].Value)
assert.Equal(t, "fish64", sch.ContentEncoding.Value) assert.Equal(t, "fish64", sch.ContentEncoding.Value)

View File

@@ -213,7 +213,7 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er
case reflect.TypeOf(NodeReference[float32]{}): case reflect.TypeOf(NodeReference[float32]{}):
if utils.IsNodeFloatValue(valueNode) { if utils.IsNodeNumberValue(valueNode) {
if field.CanSet() { if field.CanSet() {
fv, _ := strconv.ParseFloat(valueNode.Value, 32) fv, _ := strconv.ParseFloat(valueNode.Value, 32)
nr := NodeReference[float32]{ nr := NodeReference[float32]{
@@ -227,7 +227,7 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er
case reflect.TypeOf(NodeReference[float64]{}): case reflect.TypeOf(NodeReference[float64]{}):
if utils.IsNodeFloatValue(valueNode) { if utils.IsNodeNumberValue(valueNode) {
if field.CanSet() { if field.CanSet() {
fv, _ := strconv.ParseFloat(valueNode.Value, 64) fv, _ := strconv.ParseFloat(valueNode.Value, 64)
nr := NodeReference[float64]{ nr := NodeReference[float64]{

View File

@@ -408,6 +408,14 @@ func IsNodeFloatValue(node *yaml.Node) bool {
return node.Tag == "!!float" return node.Tag == "!!float"
} }
// IsNodeNumberValue will check if a node can be parsed as a float value.
func IsNodeNumberValue(node *yaml.Node) bool {
if node == nil {
return false
}
return IsNodeIntValue(node) || IsNodeFloatValue(node)
}
// IsNodeBoolValue will check is a node is a bool // IsNodeBoolValue will check is a node is a bool
func IsNodeBoolValue(node *yaml.Node) bool { func IsNodeBoolValue(node *yaml.Node) bool {
if node == nil { if node == nil {

View File

@@ -570,6 +570,23 @@ func TestIsNodeFloatValue(t *testing.T) {
assert.False(t, IsNodeFloatValue(n)) assert.False(t, IsNodeFloatValue(n))
} }
func TestIsNodeNumberValue(t *testing.T) {
n := &yaml.Node{
Tag: "!!float",
}
assert.True(t, IsNodeNumberValue(n))
n.Tag = "!!pizza"
assert.False(t, IsNodeNumberValue(n))
n = &yaml.Node{
Tag: "!!int",
}
assert.True(t, IsNodeNumberValue(n))
n.Tag = "!!pizza"
assert.False(t, IsNodeNumberValue(n))
assert.False(t, IsNodeNumberValue(nil))
}
func TestIsNodeFloatValue_Nil(t *testing.T) { func TestIsNodeFloatValue_Nil(t *testing.T) {
assert.False(t, IsNodeFloatValue(nil)) assert.False(t, IsNodeFloatValue(nil))
} }