diff --git a/.gitignore b/.gitignore index 7f91d0d..6e6d124 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -test-operation.yaml \ No newline at end of file +test-operation.yaml +.idea/ diff --git a/datamodel/high/base/schema.go b/datamodel/high/base/schema.go index 550814a..df5e1f5 100644 --- a/datamodel/high/base/schema.go +++ b/datamodel/high/base/schema.go @@ -26,12 +26,12 @@ type Schema struct { SchemaTypeRef string `json:"$schema,omitempty" yaml:"$schema,omitempty"` // In versions 2 and 3.0, this ExclusiveMaximum can only be a boolean. - // In version 3.1, ExclusiveMaximum is an integer. - ExclusiveMaximum *DynamicValue[bool, int64] `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"` + // In version 3.1, ExclusiveMaximum is a number. + ExclusiveMaximum *DynamicValue[bool, float64] `json:"exclusiveMaximum,omitempty" yaml:"exclusiveMaximum,omitempty"` - // In versions 2 and 3.0, this ExclusiveMinimum can only be a boolean. - // In version 3.1, ExclusiveMinimum is an integer. - ExclusiveMinimum *DynamicValue[bool, int64] `json:"exclusiveMinimum,omitempty" yaml:"exclusiveMinimum,omitempty"` + // In versions 2 and 3.0, this ExclusiveMinimum can only be a boolean. + // In version 3.1, ExclusiveMinimum is a number. + 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 version 3.1, Type can be multiple values @@ -74,9 +74,9 @@ type Schema struct { Not *SchemaProxy `json:"not,omitempty" yaml:"not,omitempty"` Properties map[string]*SchemaProxy `json:"properties,omitempty" yaml:"properties,omitempty"` Title string `json:"title,omitempty" yaml:"title,omitempty"` - MultipleOf *int64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"` - Maximum *int64 `json:"maximum,omitempty" yaml:"maximum,omitempty"` - Minimum *int64 `json:"minimum,omitempty" yaml:"minimum,omitempty"` + MultipleOf *float64 `json:"multipleOf,omitempty" yaml:"multipleOf,omitempty"` + Maximum *float64 `json:"maximum,omitempty" yaml:"maximum,omitempty"` + Minimum *float64 `json:"minimum,omitempty" yaml:"minimum,omitempty"` MaxLength *int64 `json:"maxLength,omitempty" yaml:"maxLength,omitempty"` MinLength *int64 `json:"minLength,omitempty" yaml:"minLength,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 !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsA() { - s.ExclusiveMaximum = &DynamicValue[bool, int64]{ + s.ExclusiveMaximum = &DynamicValue[bool, float64]{ A: schema.ExclusiveMaximum.Value.A, } } // if we're dealing with a 3.1 spec using an int if !schema.ExclusiveMaximum.IsEmpty() && schema.ExclusiveMaximum.Value.IsB() { - s.ExclusiveMaximum = &DynamicValue[bool, int64]{ + s.ExclusiveMaximum = &DynamicValue[bool, float64]{ N: 1, B: schema.ExclusiveMaximum.Value.B, } } // if we're dealing with a 3.0 spec using a bool if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsA() { - s.ExclusiveMinimum = &DynamicValue[bool, int64]{ + s.ExclusiveMinimum = &DynamicValue[bool, float64]{ A: schema.ExclusiveMinimum.Value.A, } } // if we're dealing with a 3.1 spec, using an int if !schema.ExclusiveMinimum.IsEmpty() && schema.ExclusiveMinimum.Value.IsB() { - s.ExclusiveMinimum = &DynamicValue[bool, int64]{ + s.ExclusiveMinimum = &DynamicValue[bool, float64]{ N: 1, B: schema.ExclusiveMinimum.Value.B, } diff --git a/datamodel/high/base/schema_test.go b/datamodel/high/base/schema_test.go index 1292e9d..14958d4 100644 --- a/datamodel/high/base/schema_test.go +++ b/datamodel/high/base/schema_test.go @@ -500,8 +500,8 @@ required: [cake, fish]` assert.Nil(t, schemaProxy.GetBuildError()) assert.True(t, compiled.ExclusiveMaximum.A) - assert.Equal(t, int64(123), compiled.Properties["somethingB"].Schema().ExclusiveMinimum.B) - assert.Equal(t, int64(334), compiled.Properties["somethingB"].Schema().ExclusiveMaximum.B) + assert.Equal(t, float64(123), compiled.Properties["somethingB"].Schema().ExclusiveMinimum.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.Equal(t, "nice", compiled.AdditionalProperties.(*SchemaProxy).Schema().Description) @@ -515,7 +515,7 @@ required: [cake, fish]` } func TestSchemaProxy_GoLow(t *testing.T) { - const ymlComponents = `components: + const ymlComponents = `components: schemas: rice: type: string @@ -586,25 +586,47 @@ type: number assert.Nil(t, highSchema.ExclusiveMaximum) } -func TestSchemaNumberMultipleOf(t *testing.T) { +func TestSchemaNumberMultipleOfInt(t *testing.T) { yml := ` type: number multipleOf: 5 ` highSchema := getHighSchema(t, yml) - value := int64(5) + value := float64(5) 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 := ` type: number minimum: 5 ` 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) } @@ -615,7 +637,7 @@ minimum: 0 ` highSchema := getHighSchema(t, yml) - value := int64(0) + value := float64(0) assert.EqualValues(t, &value, highSchema.Minimum) } @@ -638,7 +660,7 @@ maximum: 5 ` highSchema := getHighSchema(t, yml) - value := int64(5) + value := float64(5) assert.EqualValues(t, &value, highSchema.Maximum) } @@ -649,7 +671,7 @@ maximum: 0 ` highSchema := getHighSchema(t, yml) - value := int64(0) + value := float64(0) assert.EqualValues(t, &value, highSchema.Maximum) } diff --git a/datamodel/low/base/schema.go b/datamodel/low/base/schema.go index 4d78033..1a76457 100644 --- a/datamodel/low/base/schema.go +++ b/datamodel/low/base/schema.go @@ -52,10 +52,10 @@ type Schema struct { SchemaTypeRef low.NodeReference[string] // 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. - 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 version 3.1, Type can be multiple values @@ -94,9 +94,9 @@ type Schema struct { // Compatible with all versions Title low.NodeReference[string] - MultipleOf low.NodeReference[int64] - Maximum low.NodeReference[int64] - Minimum low.NodeReference[int64] + MultipleOf low.NodeReference[float64] + Maximum low.NodeReference[float64] + Minimum low.NodeReference[float64] MaxLength low.NodeReference[int64] MinLength low.NodeReference[int64] Pattern low.NodeReference[string] @@ -575,18 +575,18 @@ func (s *Schema) Build(root *yaml.Node, idx *index.SpecIndex) error { if exMinValue != nil { if utils.IsNodeBoolValue(exMinValue) { val, _ := strconv.ParseBool(exMinValue.Value) - s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ + s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, float64]]{ KeyNode: exMinLabel, ValueNode: exMinValue, - Value: &SchemaDynamicValue[bool, int64]{N: 0, A: val}, + Value: &SchemaDynamicValue[bool, float64]{N: 0, A: val}, } } if utils.IsNodeIntValue(exMinValue) { - val, _ := strconv.ParseInt(exMinValue.Value, 10, 64) - s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ + val, _ := strconv.ParseFloat(exMinValue.Value, 64) + s.ExclusiveMinimum = low.NodeReference[*SchemaDynamicValue[bool, float64]]{ KeyNode: exMinLabel, 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 utils.IsNodeBoolValue(exMaxValue) { val, _ := strconv.ParseBool(exMaxValue.Value) - s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ + s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, float64]]{ KeyNode: exMaxLabel, ValueNode: exMaxValue, - Value: &SchemaDynamicValue[bool, int64]{N: 0, A: val}, + Value: &SchemaDynamicValue[bool, float64]{N: 0, A: val}, } } if utils.IsNodeIntValue(exMaxValue) { - val, _ := strconv.ParseInt(exMaxValue.Value, 10, 64) - s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, int64]]{ + val, _ := strconv.ParseFloat(exMaxValue.Value, 64) + s.ExclusiveMaximum = low.NodeReference[*SchemaDynamicValue[bool, float64]]{ KeyNode: exMaxLabel, ValueNode: exMaxValue, - Value: &SchemaDynamicValue[bool, int64]{N: 1, B: val}, + Value: &SchemaDynamicValue[bool, float64]{N: 1, B: val}, } } } diff --git a/datamodel/low/base/schema_test.go b/datamodel/low/base/schema_test.go index 7f5eacb..34a9942 100644 --- a/datamodel/low/base/schema_test.go +++ b/datamodel/low/base/schema_test.go @@ -424,8 +424,8 @@ examples: assert.True(t, sch.ExclusiveMinimum.Value.IsB()) assert.False(t, sch.ExclusiveMinimum.Value.IsA()) assert.True(t, sch.ExclusiveMaximum.Value.IsB()) - assert.Equal(t, int64(12), sch.ExclusiveMinimum.Value.B) - assert.Equal(t, int64(13), sch.ExclusiveMaximum.Value.B) + assert.Equal(t, float64(12), sch.ExclusiveMinimum.Value.B) + assert.Equal(t, float64(13), sch.ExclusiveMaximum.Value.B) assert.Len(t, sch.Examples.Value, 1) assert.Equal(t, "testing", sch.Examples.Value[0].Value) assert.Equal(t, "fish64", sch.ContentEncoding.Value) diff --git a/datamodel/low/model_builder.go b/datamodel/low/model_builder.go index deb1400..14b46e3 100644 --- a/datamodel/low/model_builder.go +++ b/datamodel/low/model_builder.go @@ -213,7 +213,7 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er case reflect.TypeOf(NodeReference[float32]{}): - if utils.IsNodeFloatValue(valueNode) { + if utils.IsNodeNumberValue(valueNode) { if field.CanSet() { fv, _ := strconv.ParseFloat(valueNode.Value, 32) nr := NodeReference[float32]{ @@ -227,7 +227,7 @@ func SetField(field *reflect.Value, valueNode *yaml.Node, keyNode *yaml.Node) er case reflect.TypeOf(NodeReference[float64]{}): - if utils.IsNodeFloatValue(valueNode) { + if utils.IsNodeNumberValue(valueNode) { if field.CanSet() { fv, _ := strconv.ParseFloat(valueNode.Value, 64) nr := NodeReference[float64]{ diff --git a/utils/utils.go b/utils/utils.go index d9c27e5..07eb636 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -408,6 +408,14 @@ func IsNodeFloatValue(node *yaml.Node) bool { 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 func IsNodeBoolValue(node *yaml.Node) bool { if node == nil { diff --git a/utils/utils_test.go b/utils/utils_test.go index 57ec358..009faf1 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -570,6 +570,23 @@ func TestIsNodeFloatValue(t *testing.T) { 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) { assert.False(t, IsNodeFloatValue(nil)) }