jsonschema: validate numbers and strings

Add validation for keywords related to numbers and strings.

It may be surprising that keywords like "minimum" or "minLength"
don't imply that the instance is a number or string.
But that is how JSON Schema is designed.

Change-Id: I8805a5fe91ee345931e1c989f174ea2d0be6665a
Reviewed-on: https://go-review.googlesource.com/c/tools/+/667975
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Auto-Submit: Jonathan Amsterdam <jba@google.com>
This commit is contained in:
Jonathan Amsterdam 2025-04-24 19:18:21 -04:00 • committed by Gopher Robot
commit 061f842459
8 changed files with 532 additions and 0 deletions

View file

@ -0,0 +1,31 @@
[
{
"description": "exclusiveMaximum validation",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"exclusiveMaximum": 3.0
},
"tests": [
{
"description": "below the exclusiveMaximum is valid",
"data": 2.2,
"valid": true
},
{
"description": "boundary point is invalid",
"data": 3.0,
"valid": false
},
{
"description": "above the exclusiveMaximum is invalid",
"data": 3.5,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
}
]

View file

@ -0,0 +1,31 @@
[
{
"description": "exclusiveMinimum validation",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"exclusiveMinimum": 1.1
},
"tests": [
{
"description": "above the exclusiveMinimum is valid",
"data": 1.2,
"valid": true
},
{
"description": "boundary point is invalid",
"data": 1.1,
"valid": false
},
{
"description": "below the exclusiveMinimum is invalid",
"data": 0.6,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
}
]

View file

@ -0,0 +1,55 @@
[
{
"description": "maxLength validation",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"maxLength": 2
},
"tests": [
{
"description": "shorter is valid",
"data": "f",
"valid": true
},
{
"description": "exact length is valid",
"data": "fo",
"valid": true
},
{
"description": "too long is invalid",
"data": "foo",
"valid": false
},
{
"description": "ignores non-strings",
"data": 100,
"valid": true
},
{
"description": "two graphemes is long enough",
"data": "\uD83D\uDCA9\uD83D\uDCA9",
"valid": true
}
]
},
{
"description": "maxLength validation with a decimal",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"maxLength": 2.0
},
"tests": [
{
"description": "shorter is valid",
"data": "f",
"valid": true
},
{
"description": "too long is invalid",
"data": "foo",
"valid": false
}
]
}
]

View file

@ -0,0 +1,60 @@
[
{
"description": "maximum validation",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"maximum": 3.0
},
"tests": [
{
"description": "below the maximum is valid",
"data": 2.6,
"valid": true
},
{
"description": "boundary point is valid",
"data": 3.0,
"valid": true
},
{
"description": "above the maximum is invalid",
"data": 3.5,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
},
{
"description": "maximum validation with unsigned integer",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"maximum": 300
},
"tests": [
{
"description": "below the maximum is invalid",
"data": 299.97,
"valid": true
},
{
"description": "boundary point integer is valid",
"data": 300,
"valid": true
},
{
"description": "boundary point float is valid",
"data": 300.00,
"valid": true
},
{
"description": "above the maximum is invalid",
"data": 300.5,
"valid": false
}
]
}
]

View file

@ -0,0 +1,55 @@
[
{
"description": "minLength validation",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"minLength": 2
},
"tests": [
{
"description": "longer is valid",
"data": "foo",
"valid": true
},
{
"description": "exact length is valid",
"data": "fo",
"valid": true
},
{
"description": "too short is invalid",
"data": "f",
"valid": false
},
{
"description": "ignores non-strings",
"data": 1,
"valid": true
},
{
"description": "one grapheme is not long enough",
"data": "\uD83D\uDCA9",
"valid": false
}
]
},
{
"description": "minLength validation with a decimal",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"minLength": 2.0
},
"tests": [
{
"description": "longer is valid",
"data": "foo",
"valid": true
},
{
"description": "too short is invalid",
"data": "f",
"valid": false
}
]
}
]

View file

@ -0,0 +1,75 @@
[
{
"description": "minimum validation",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"minimum": 1.1
},
"tests": [
{
"description": "above the minimum is valid",
"data": 2.6,
"valid": true
},
{
"description": "boundary point is valid",
"data": 1.1,
"valid": true
},
{
"description": "below the minimum is invalid",
"data": 0.6,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
},
{
"description": "minimum validation with signed integer",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"minimum": -2
},
"tests": [
{
"description": "negative above the minimum is valid",
"data": -1,
"valid": true
},
{
"description": "positive above the minimum is valid",
"data": 0,
"valid": true
},
{
"description": "boundary point is valid",
"data": -2,
"valid": true
},
{
"description": "boundary point with float is valid",
"data": -2.0,
"valid": true
},
{
"description": "float below the minimum is invalid",
"data": -2.0001,
"valid": false
},
{
"description": "int below the minimum is invalid",
"data": -3,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "x",
"valid": true
}
]
}
]

View file

@ -0,0 +1,97 @@
[
{
"description": "by int",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"multipleOf": 2
},
"tests": [
{
"description": "int by int",
"data": 10,
"valid": true
},
{
"description": "int by int fail",
"data": 7,
"valid": false
},
{
"description": "ignores non-numbers",
"data": "foo",
"valid": true
}
]
},
{
"description": "by number",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"multipleOf": 1.5
},
"tests": [
{
"description": "zero is multiple of anything",
"data": 0,
"valid": true
},
{
"description": "4.5 is multiple of 1.5",
"data": 4.5,
"valid": true
},
{
"description": "35 is not multiple of 1.5",
"data": 35,
"valid": false
}
]
},
{
"description": "by small number",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"multipleOf": 0.0001
},
"tests": [
{
"description": "0.0075 is multiple of 0.0001",
"data": 0.0075,
"valid": true
},
{
"description": "0.00751 is not multiple of 0.0001",
"data": 0.00751,
"valid": false
}
]
},
{
"description": "float division = inf",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "integer", "multipleOf": 0.123456789
},
"tests": [
{
"description": "always invalid, but naive implementations may raise an overflow error",
"data": 1e308,
"valid": false
}
]
},
{
"description": "small multiple of large integer",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "integer", "multipleOf": 1e-8
},
"tests": [
{
"description": "any integer is a multiple of 1e-8",
"data": 12391239123,
"valid": true
}
]
}
]

View file

@ -0,0 +1,65 @@
[
{
"description": "pattern validation",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"pattern": "^a*$"
},
"tests": [
{
"description": "a matching pattern is valid",
"data": "aaa",
"valid": true
},
{
"description": "a non-matching pattern is invalid",
"data": "abc",
"valid": false
},
{
"description": "ignores booleans",
"data": true,
"valid": true
},
{
"description": "ignores integers",
"data": 123,
"valid": true
},
{
"description": "ignores floats",
"data": 1.0,
"valid": true
},
{
"description": "ignores objects",
"data": {},
"valid": true
},
{
"description": "ignores arrays",
"data": [],
"valid": true
},
{
"description": "ignores null",
"data": null,
"valid": true
}
]
},
{
"description": "pattern is not anchored",
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"pattern": "a+"
},
"tests": [
{
"description": "matches a substring",
"data": "xxaayy",
"valid": true
}
]
}
]