Skip to content

Commit d4bdebd

Browse files
authored
openapi3: replace bigfloat with decimal128 to fix rounding errors during validation (#1068)
* fix: replace bigfloat with decimal128 * update tests
1 parent bf26c56 commit d4bdebd

File tree

4 files changed

+47
-1
lines changed

4 files changed

+47
-1
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ require (
1010
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90
1111
github.com/perimeterx/marshmallow v1.1.5
1212
github.com/stretchr/testify v1.9.0
13+
github.com/woodsbury/decimal128 v1.3.0
1314
)
1415

1516
require (

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
3232
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
3333
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
3434
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
35+
github.com/woodsbury/decimal128 v1.3.0 h1:8pffMNWIlC0O5vbyHWFZAt5yWvWcrHA+3ovIIjVWss0=
36+
github.com/woodsbury/decimal128 v1.3.0/go.mod h1:C5UTmyTjW3JftjUFzOVhC20BEQa2a4ZKOB5I6Zjb+ds=
3537
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
3638
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
3739
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

openapi3/schema.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717

1818
"github.com/go-openapi/jsonpointer"
1919
"github.com/mohae/deepcopy"
20+
"github.com/woodsbury/decimal128"
2021
)
2122

2223
const (
@@ -1643,7 +1644,10 @@ func (schema *Schema) visitJSONNumber(settings *schemaValidationSettings, value
16431644
if v := schema.MultipleOf; v != nil {
16441645
// "A numeric instance is valid only if division by this keyword's
16451646
// value results in an integer."
1646-
if bigFloat := big.NewFloat(value / *v); !bigFloat.IsInt() {
1647+
numParsed, _ := decimal128.Parse(fmt.Sprintf("%.10f", value))
1648+
denParsed, _ := decimal128.Parse(fmt.Sprintf("%.10f", *v))
1649+
_, remainder := numParsed.QuoRem(denParsed)
1650+
if !remainder.IsZero() {
16471651
if settings.failfast {
16481652
return errSchema
16491653
}

openapi3/schema_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"encoding/base64"
66
"encoding/json"
7+
"fmt"
78
"math"
89
"reflect"
910
"strings"
@@ -1490,3 +1491,41 @@ func TestIssue751(t *testing.T) {
14901491
require.NoError(t, schema.VisitJSON(validData))
14911492
require.ErrorContains(t, schema.VisitJSON(invalidData), "duplicate items found")
14921493
}
1494+
1495+
func TestIssue817(t *testing.T) {
1496+
max := 999999999.99
1497+
min := -999999999.99
1498+
mulOf := 0.01
1499+
schema := &Schema{
1500+
Type: &Types{"number"},
1501+
Max: &max,
1502+
Min: &min,
1503+
MultipleOf: &mulOf,
1504+
}
1505+
validData := []float64{2.07, 8.1, 19628.87, 323.39, 40428.2, 1.13}
1506+
for _, data := range validData {
1507+
require.NoError(t, schema.VisitJSON(data))
1508+
}
1509+
1510+
invalidData := []struct {
1511+
mulfOf float64
1512+
data float64
1513+
}{
1514+
{
1515+
mulfOf: 0.01,
1516+
data: 0.005,
1517+
},
1518+
{
1519+
mulfOf: 3.0,
1520+
data: 5.0,
1521+
},
1522+
{
1523+
mulfOf: 5.0,
1524+
data: 2.0,
1525+
},
1526+
}
1527+
for _, data := range invalidData {
1528+
schema.MultipleOf = &data.mulfOf
1529+
require.ErrorContains(t, schema.VisitJSON(data.data), fmt.Sprintf("number must be a multiple of %+v", data.mulfOf))
1530+
}
1531+
}

0 commit comments

Comments
 (0)