Skip to content

Add boundary cases for integers #774

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion tests/draft-next/type.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,48 @@
"data": 1,
"valid": true
},
{
"description": "a negative integer is an integer",
"data": -1,
"valid": true
},
{
"description": "zero is an integer",
"data": 0,
"valid": true
},
{
"description": "negative zero is an integer",
"data": -0,
"valid": true
},
{
"description": "a float with zero fractional part is an integer",
"data": 1.0,
"valid": true
},
{
"description": "a float is not an integer",
"description": "a float with an exponent and a zero fractional part is an integer",
"data": 1e0,
"valid": true
},
{
"description": "a small float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 1.00000000000001,
"valid": true
},
{
"description": "a large float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 9007199254740991.5,
"valid": true
},
Comment on lines +40 to +48
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karenetheridge is correct. These are not integers. JSON Schema uses an object model based on the one defined by the JSON specification, RFC 8259, which does not put limits on numeric values. Range does not matter. See Core 6.2 and Validation 4.2.

We do already have some tests for extremely large numbers. They are in the optional folders as we recognize that they typically are not fully supported and are generally edge-case. An argument could be made that they should not be optional.

{
"description": "a number near the maximum representable value for a binary64 float is an integer",
"data": 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368,
"valid": true
},
{
"description": "a float with a non-zero fractional part is not an integer",
"data": 1.1,
"valid": false
},
Expand Down
37 changes: 36 additions & 1 deletion tests/draft2019-09/type.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,48 @@
"data": 1,
"valid": true
},
{
"description": "a negative integer is an integer",
"data": -1,
"valid": true
},
{
"description": "zero is an integer",
"data": 0,
"valid": true
},
{
"description": "negative zero is an integer",
"data": -0,
"valid": true
},
{
"description": "a float with zero fractional part is an integer",
"data": 1.0,
"valid": true
},
{
"description": "a float is not an integer",
"description": "a float with an exponent and a zero fractional part is an integer",
"data": 1e0,
"valid": true
},
{
"description": "a small float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 1.00000000000001,
"valid": true
},
{
"description": "a large float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 9007199254740991.5,
"valid": true
},
{
"description": "a number near the maximum representable value for a binary64 float is an integer",
"data": 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368,
"valid": true
},
{
"description": "a float with a non-zero fractional part is not an integer",
"data": 1.1,
"valid": false
},
Expand Down
37 changes: 36 additions & 1 deletion tests/draft2020-12/type.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,48 @@
"data": 1,
"valid": true
},
{
"description": "a negative integer is an integer",
"data": -1,
"valid": true
},
{
"description": "zero is an integer",
"data": 0,
"valid": true
},
{
"description": "negative zero is an integer",
"data": -0,
"valid": true
},
{
"description": "a float with zero fractional part is an integer",
"data": 1.0,
"valid": true
},
{
"description": "a float is not an integer",
"description": "a float with an exponent and a zero fractional part is an integer",
"data": 1e0,
"valid": true
},
{
"description": "a small float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 1.00000000000001,
"valid": true
},
{
"description": "a large float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 9007199254740991.5,
"valid": true
},
{
"description": "a number near the maximum representable value for a binary64 float is an integer",
"data": 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368,
"valid": true
},
{
"description": "a float with a non-zero fractional part is not an integer",
"data": 1.1,
"valid": false
},
Expand Down
42 changes: 41 additions & 1 deletion tests/draft3/type.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,47 @@
"valid": true
},
{
"description": "a float is not an integer",
"description": "a negative integer is an integer",
"data": -1,
"valid": true
},
{
"description": "zero is an integer",
"data": 0,
"valid": true
},
{
"description": "negative zero is an integer",
"data": -0,
"valid": true
},
{
"description": "a float with zero fractional part is an integer",
"data": 1.0,
"valid": true
},
Comment on lines +26 to +30
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this wasn't included in draft3 already, but there might be a reason!

{
"description": "a float with an exponent and a zero fractional part is an integer",
"data": 1e0,
"valid": true
},
{
"description": "a small float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 1.00000000000001,
"valid": true
},
{
"description": "a large float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 9007199254740991.5,
"valid": true
},
{
"description": "a number near the maximum representable value for a binary64 float is an integer",
"data": 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368,
"valid": true
},
{
"description": "a float with a non-zero fractional part is not an integer",
"data": 1.1,
"valid": false
},
Expand Down
42 changes: 41 additions & 1 deletion tests/draft4/type.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,47 @@
"valid": true
},
{
"description": "a float is not an integer",
"description": "a negative integer is an integer",
"data": -1,
"valid": true
},
{
"description": "zero is an integer",
"data": 0,
"valid": true
},
{
"description": "negative zero is an integer",
"data": -0,
"valid": true
},
{
"description": "a float with zero fractional part is an integer",
"data": 1.0,
"valid": true
},
Comment on lines +26 to +30
Copy link
Author

@hudlow hudlow May 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this wasn't included in draft4 already, but there might be a reason!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

draft4 and earlier have different integer semantics: in draft4, an integer is "A JSON number without a fraction or exponent part", therefore 1.0 is NOT an integer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There ought to be a draft4 test for 1.0 not being an integer, but I only see one that confirms it is a number (but that's not sufficient because all integers are also numbers).

{
"description": "a float with an exponent and a zero fractional part is an integer",
"data": 1e0,
"valid": true
},
{
"description": "a small float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 1.00000000000001,
"valid": true
},
{
"description": "a large float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 9007199254740991.5,
"valid": true
},
{
"description": "a number near the maximum representable value for a binary64 float is an integer",
"data": 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368,
"valid": true
},
{
"description": "a float with a non-zero fractional part is not an integer",
"data": 1.1,
"valid": false
},
Expand Down
37 changes: 36 additions & 1 deletion tests/draft6/type.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,48 @@
"data": 1,
"valid": true
},
{
"description": "a negative integer is an integer",
"data": -1,
"valid": true
},
{
"description": "zero is an integer",
"data": 0,
"valid": true
},
{
"description": "negative zero is an integer",
"data": -0,
"valid": true
},
{
"description": "a float with zero fractional part is an integer",
"data": 1.0,
"valid": true
},
{
"description": "a float is not an integer",
"description": "a float with an exponent and a zero fractional part is an integer",
"data": 1e0,
"valid": true
},
{
"description": "a small float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 1.00000000000001,
"valid": true
},
{
"description": "a large float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 9007199254740991.5,
"valid": true
},
{
"description": "a number near the maximum representable value for a binary64 float is an integer",
"data": 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368,
"valid": true
},
{
"description": "a float with a non-zero fractional part is not an integer",
"data": 1.1,
"valid": false
},
Expand Down
37 changes: 36 additions & 1 deletion tests/draft7/type.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,48 @@
"data": 1,
"valid": true
},
{
"description": "a negative integer is an integer",
"data": -1,
"valid": true
},
{
"description": "zero is an integer",
"data": 0,
"valid": true
},
{
"description": "negative zero is an integer",
"data": -0,
"valid": true
},
{
"description": "a float with zero fractional part is an integer",
"data": 1.0,
"valid": true
},
{
"description": "a float is not an integer",
"description": "a float with an exponent and a zero fractional part is an integer",
"data": 1e0,
"valid": true
},
{
"description": "a small float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 1.00000000000001,
"valid": true
},
{
"description": "a large float whose non-zero fractional part is truncated in a binary64 float is an integer",
"data": 9007199254740991.5,
"valid": true
},
{
"description": "a number near the maximum representable value for a binary64 float is an integer",
"data": 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368,
"valid": true
},
{
"description": "a float with a non-zero fractional part is not an integer",
"data": 1.1,
"valid": false
},
Expand Down
Loading