Skip to content

Commit

Permalink
encoding/jsonschema: allow whole floats for unsigned numbers
Browse files Browse the repository at this point in the history
JSON does not make a distinction between floats and ints,
and there are tests in the jsonschema test suite that check that
it's OK to use floating point literals in primitives that expect
an integer.

So accept whole floats anywhere we need a uint.

Relevant issue: #253.

Signed-off-by: Roger Peppe <[email protected]>
Change-Id: I44632a6eadd2aeaff626b27ca6536d4aa47035aa
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1200939
Unity-Result: CUE porcuepine <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
Reviewed-by: Daniel Martí <[email protected]>
  • Loading branch information
rogpeppe committed Sep 10, 2024
1 parent 8507a5a commit 3a11f99
Show file tree
Hide file tree
Showing 23 changed files with 81 additions and 293 deletions.
6 changes: 3 additions & 3 deletions encoding/jsonschema/constraints_array.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func constraintAdditionalItems(key string, n cue.Value, s *state) {
}

func constraintMinContains(key string, n cue.Value, s *state) {
p, err := n.Uint64()
p, err := uint64Value(n)
if err != nil {
s.errf(n, `value of "minContains" must be a non-negative integer value`)
return
Expand All @@ -50,7 +50,7 @@ func constraintMinContains(key string, n cue.Value, s *state) {
}

func constraintMaxContains(key string, n cue.Value, s *state) {
p, err := n.Uint64()
p, err := uint64Value(n)
if err != nil {
s.errf(n, `value of "maxContains" must be a non-negative integer value`)
return
Expand Down Expand Up @@ -112,7 +112,7 @@ func constraintMaxItems(key string, n cue.Value, s *state) {

func constraintMinItems(key string, n cue.Value, s *state) {
a := []ast.Expr{}
p, err := n.Uint64()
p, err := uint64Value(n)
if err != nil {
s.errf(n, "invalid uint")
}
Expand Down
36 changes: 32 additions & 4 deletions encoding/jsonschema/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ package jsonschema

import (
"fmt"
"math"
"net/url"
"sort"
"strconv"
"strings"

"cuelang.org/go/cue"
Expand Down Expand Up @@ -221,12 +223,16 @@ func (d *decoder) number(n cue.Value) ast.Expr {
return n.Syntax(cue.Final()).(ast.Expr)
}

func (d *decoder) uint(n cue.Value) ast.Expr {
_, err := n.Uint64()
func (d *decoder) uint(nv cue.Value) ast.Expr {
n, err := uint64Value(nv)
if err != nil {
d.errf(n, "invalid uint")
d.errf(nv, "invalid uint")
}
return &ast.BasicLit{
ValuePos: nv.Pos(),
Kind: token.FLOAT,
Value: strconv.FormatUint(n, 10),
}
return n.Syntax(cue.Final()).(ast.Expr)
}

func (d *decoder) boolValue(n cue.Value) bool {
Expand Down Expand Up @@ -811,3 +817,25 @@ func setPos(e ast.Expr, v cue.Value) ast.Expr {
ast.SetPos(e, v.Pos())
return e
}

// uint64Value is like v.Uint64 except that it
// also allows floating point constants, as long
// as they have no fractional part.
func uint64Value(v cue.Value) (uint64, error) {
n, err := v.Uint64()
if err == nil {
return n, nil
}
f, err := v.Float64()
if err != nil {
return 0, err
}
intPart, fracPart := math.Modf(f)
if fracPart != 0 {
return 0, errors.Newf(v.Pos(), "%v is not a whole number", v)
}
if intPart < 0 || intPart > math.MaxUint64 {
return 0, errors.Newf(v.Pos(), "%v is out of bounds", v)
}
return uint64(intPart), nil
}
12 changes: 6 additions & 6 deletions encoding/jsonschema/external_teststats.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Generated by teststats. DO NOT EDIT
v2:
schema extract (pass / total): 1020 / 1637 = 62.3%
tests (pass / total): 3338 / 7175 = 46.5%
tests on extracted schemas (pass / total): 3338 / 3752 = 89.0%
schema extract (pass / total): 1040 / 1637 = 63.5%
tests (pass / total): 3378 / 7175 = 47.1%
tests on extracted schemas (pass / total): 3378 / 3792 = 89.1%

v3:
schema extract (pass / total): 1008 / 1637 = 61.6%
tests (pass / total): 3289 / 7175 = 45.8%
tests on extracted schemas (pass / total): 3289 / 3708 = 88.7%
schema extract (pass / total): 1028 / 1637 = 62.8%
tests (pass / total): 3329 / 7175 = 46.4%
tests on extracted schemas (pass / total): 3329 / 3748 = 88.8%
Original file line number Diff line number Diff line change
Expand Up @@ -81,33 +81,21 @@
},
"maxContains": 1.0
},
"skip": {
"v2": "extract error: value of \"maxContains\" must be a non-negative integer value",
"v3": "extract error: value of \"maxContains\" must be a non-negative integer value"
},
"tests": [
{
"description": "one element matches, valid maxContains",
"data": [
1
],
"valid": true,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": true
},
{
"description": "too many elements match, invalid maxContains",
"data": [
1,
1
],
"valid": false,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": false
}
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,13 @@
"$schema": "https://json-schema.org/draft/2019-09/schema",
"maxItems": 2.0
},
"skip": {
"v2": "extract error: invalid uint",
"v3": "extract error: invalid uint"
},
"tests": [
{
"description": "shorter is valid",
"data": [
1
],
"valid": true,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": true
},
{
"description": "too long is invalid",
Expand All @@ -66,11 +58,7 @@
2,
3
],
"valid": false,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": false
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,13 @@
"$schema": "https://json-schema.org/draft/2019-09/schema",
"maxProperties": 2.0
},
"skip": {
"v2": "extract error: invalid uint",
"v3": "extract error: invalid uint"
},
"tests": [
{
"description": "shorter is valid",
"data": {
"foo": 1
},
"valid": true,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": true
},
{
"description": "too long is invalid",
Expand All @@ -80,11 +72,7 @@
"bar": 2,
"baz": 3
},
"valid": false,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": false
}
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,33 +134,21 @@
},
"minContains": 2.0
},
"skip": {
"v2": "extract error: value of \"minContains\" must be a non-negative integer value",
"v3": "extract error: value of \"minContains\" must be a non-negative integer value"
},
"tests": [
{
"description": "one element matches, invalid minContains",
"data": [
1
],
"valid": false,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": false
},
{
"description": "both elements match, valid minContains",
"data": [
1,
1
],
"valid": true,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": true
}
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,31 +39,19 @@
"$schema": "https://json-schema.org/draft/2019-09/schema",
"minItems": 1.0
},
"skip": {
"v2": "extract error: invalid uint",
"v3": "extract error: invalid uint"
},
"tests": [
{
"description": "longer is valid",
"data": [
1,
2
],
"valid": true,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": true
},
{
"description": "too short is invalid",
"data": [],
"valid": false,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": false
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,31 +49,19 @@
"$schema": "https://json-schema.org/draft/2019-09/schema",
"minProperties": 1.0
},
"skip": {
"v2": "extract error: invalid uint",
"v3": "extract error: invalid uint"
},
"tests": [
{
"description": "longer is valid",
"data": {
"foo": 1,
"bar": 2
},
"valid": true,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": true
},
{
"description": "too short is invalid",
"data": {},
"valid": false,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": false
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,33 +81,21 @@
},
"maxContains": 1.0
},
"skip": {
"v2": "extract error: value of \"maxContains\" must be a non-negative integer value",
"v3": "extract error: value of \"maxContains\" must be a non-negative integer value"
},
"tests": [
{
"description": "one element matches, valid maxContains",
"data": [
1
],
"valid": true,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": true
},
{
"description": "too many elements match, invalid maxContains",
"data": [
1,
1
],
"valid": false,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": false
}
]
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,13 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"maxItems": 2.0
},
"skip": {
"v2": "extract error: invalid uint",
"v3": "extract error: invalid uint"
},
"tests": [
{
"description": "shorter is valid",
"data": [
1
],
"valid": true,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": true
},
{
"description": "too long is invalid",
Expand All @@ -66,11 +58,7 @@
2,
3
],
"valid": false,
"skip": {
"v2": "could not compile schema",
"v3": "could not compile schema"
}
"valid": false
}
]
}
Expand Down
Loading

0 comments on commit 3a11f99

Please sign in to comment.