Skip to content

Commit db21d21

Browse files
committed
Merge branch 'main' into hostname-format-check-empty-string
2 parents 202d562 + 82a0774 commit db21d21

File tree

156 files changed

+4055
-1724
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

156 files changed

+4055
-1724
lines changed

.github/workflows/pr-dependencies.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: Check PR Dependencies
2+
3+
on: pull_request
4+
5+
jobs:
6+
check_dependencies:
7+
runs-on: ubuntu-latest
8+
name: Check Dependencies
9+
steps:
10+
- uses: gregsdennis/dependencies-action@main
11+
env:
12+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Show Specification Annotations
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- 'tests/**'
7+
8+
jobs:
9+
annotate:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Set up Python
16+
uses: actions/setup-python@v5
17+
with:
18+
python-version: '3.x'
19+
20+
- name: Generate Annotations
21+
run: pip install uritemplate && bin/annotate-specification-links

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ To test a specific version:
109109

110110
* For 2019-09 and later published drafts, implementations that are able to detect the draft of each schema via `$schema` SHOULD be configured to do so
111111
* For draft-07 and earlier, draft-next, and implementations unable to detect via `$schema`, implementations MUST be configured to expect the draft matching the test directory name
112-
* Load any remote references [described below](additional-assumptions) and configure your implementation to retrieve them via their URIs
112+
* Load any remote references [described below](#additional-assumptions) and configure your implementation to retrieve them via their URIs
113113
* Walk the filesystem tree for that version's subdirectory and for each `.json` file found:
114114

115115
* if the file is located in the root of the version directory:
@@ -159,7 +159,7 @@ If your implementation supports multiple versions, run the above procedure for e
159159
```
160160
161161
2. Test cases found within [special subdirectories](#subdirectories-within-each-draft) may require additional configuration to run.
162-
In particular, tests within the `optional/format` subdirectory may require implementations to change the way they treat the `"format"`keyword (particularly on older drafts which did not have a notion of vocabularies).
162+
In particular, when running tests within the `optional/format` subdirectory, test runners should configure implementations to enable format validation, where the implementation supports it.
163163
164164
### Invariants & Guarantees
165165
@@ -254,12 +254,14 @@ This suite is being used by:
254254

255255
### Java
256256

257+
* [json-schema-validation-comparison](https://www.creekservice.org/json-schema-validation-comparison/functional) (Comparison site for JVM-based validator implementations)
257258
* [json-schema-validator](https://github.com/daveclayton/json-schema-validator)
258259
* [everit-org/json-schema](https://github.com/everit-org/json-schema)
259260
* [networknt/json-schema-validator](https://github.com/networknt/json-schema-validator)
260261
* [Justify](https://github.com/leadpony/justify)
261262
* [Snow](https://github.com/ssilverman/snowy-json)
262263
* [jsonschemafriend](https://github.com/jimblackler/jsonschemafriend)
264+
* [OpenAPI JSON Schema Generator](https://github.com/openapi-json-schema-tools/openapi-json-schema-generator)
263265

264266
### JavaScript
265267

@@ -279,6 +281,10 @@ This suite is being used by:
279281
* [ajv](https://github.com/epoberezkin/ajv)
280282
* [djv](https://github.com/korzio/djv)
281283

284+
### Kotlin
285+
286+
* [json-schema-validation-comparison](https://www.creekservice.org/json-schema-validation-comparison/functional) (Comparison site for JVM-based validator implementations)
287+
282288
### Node.js
283289

284290
For node.js developers, the suite is also available as an [npm](https://www.npmjs.com/package/@json-schema-org/tests) package.
@@ -313,7 +319,7 @@ Node-specific support is maintained in a [separate repository](https://github.co
313319
* [fastjsonschema](https://github.com/seznam/python-fastjsonschema)
314320
* [hypothesis-jsonschema](https://github.com/Zac-HD/hypothesis-jsonschema)
315321
* [jschon](https://github.com/marksparkza/jschon)
316-
* [python-experimental, OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator/blob/master/docs/generators/python-experimental.md)
322+
* [OpenAPI JSON Schema Generator](https://github.com/openapi-json-schema-tools/openapi-json-schema-generator)
317323

318324
### Ruby
319325

@@ -327,6 +333,7 @@ Node-specific support is maintained in a [separate repository](https://github.co
327333

328334
### Scala
329335

336+
* [json-schema-validation-comparison](https://www.creekservice.org/json-schema-validation-comparison/functional) (Comparison site for JVM-based validator implementations)
330337
* [typed-json](https://github.com/frawa/typed-json)
331338

332339
### Swift

bin/annotate-specification-links

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Annotate pull requests to the GitHub repository with links to specifications.
4+
"""
5+
6+
from __future__ import annotations
7+
8+
from pathlib import Path
9+
from typing import Any
10+
import json
11+
import re
12+
import sys
13+
14+
from uritemplate import URITemplate
15+
16+
17+
BIN_DIR = Path(__file__).parent
18+
TESTS = BIN_DIR.parent / "tests"
19+
URLS = json.loads(BIN_DIR.joinpath("specification_urls.json").read_text())
20+
21+
22+
def urls(version: str) -> dict[str, URITemplate]:
23+
"""
24+
Retrieve the version-specific URLs for specifications.
25+
"""
26+
for_version = {**URLS["json-schema"][version], **URLS["external"]}
27+
return {k: URITemplate(v) for k, v in for_version.items()}
28+
29+
30+
def annotation(
31+
path: Path,
32+
message: str,
33+
line: int = 1,
34+
level: str = "notice",
35+
**kwargs: Any,
36+
) -> str:
37+
"""
38+
Format a GitHub annotation.
39+
40+
See https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions
41+
for full syntax.
42+
"""
43+
44+
if kwargs:
45+
additional = "," + ",".join(f"{k}={v}" for k, v in kwargs.items())
46+
else:
47+
additional = ""
48+
49+
relative = path.relative_to(TESTS.parent)
50+
return f"::{level} file={relative},line={line}{additional}::{message}\n"
51+
52+
53+
def line_number_of(path: Path, case: dict[str, Any]) -> int:
54+
"""
55+
Crudely find the line number of a test case.
56+
"""
57+
with path.open() as file:
58+
description = case["description"]
59+
return next(
60+
(i + 1 for i, line in enumerate(file, 1) if description in line),
61+
1,
62+
)
63+
64+
65+
def main():
66+
# Clear annotations which may have been emitted by a previous run.
67+
sys.stdout.write("::remove-matcher owner=me::\n")
68+
69+
for version in TESTS.iterdir():
70+
if version.name in {"draft-next", "latest"}:
71+
continue
72+
73+
version_urls = urls(version.name)
74+
75+
for path in version.rglob("*.json"):
76+
try:
77+
contents = json.loads(path.read_text())
78+
except json.JSONDecodeError as error:
79+
error = annotation(
80+
level="error",
81+
path=path,
82+
line=error.lineno,
83+
col=error.pos + 1,
84+
title=str(error),
85+
)
86+
sys.stdout.write(error)
87+
88+
for test_case in contents:
89+
specifications = test_case.get("specification")
90+
if specifications is not None:
91+
for each in specifications:
92+
quote = each.pop("quote", "")
93+
(kind, section), = each.items()
94+
95+
number = re.search(r"\d+", kind)
96+
spec = "" if number is None else number.group(0)
97+
98+
url = version_urls[kind].expand(
99+
spec=spec,
100+
section=section,
101+
)
102+
103+
message = f"{url}\n\n{quote}" if quote else url
104+
sys.stdout.write(
105+
annotation(
106+
path=path,
107+
line=line_number_of(path, test_case),
108+
title="Specification Link",
109+
message=message,
110+
),
111+
)
112+
113+
114+
if __name__ == "__main__":
115+
main()

bin/jsonschema_suite

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ import warnings
1414
try:
1515
import jsonschema.validators
1616
except ImportError:
17-
jsonschema = None
17+
jsonschema = Unresolvable = None
1818
VALIDATORS = {}
1919
else:
20+
from referencing.exceptions import Unresolvable
21+
2022
VALIDATORS = {
2123
"draft3": jsonschema.validators.Draft3Validator,
2224
"draft4": jsonschema.validators.Draft4Validator,
@@ -587,7 +589,7 @@ class SanityTests(unittest.TestCase):
587589
with self.subTest(case=case, version=version.name):
588590
try:
589591
Validator(case["schema"]).is_valid(12)
590-
except jsonschema.exceptions.RefResolutionError:
592+
except Unresolvable:
591593
pass
592594

593595
@unittest.skipIf(jsonschema is None, "Validation library not present!")
@@ -615,9 +617,6 @@ class SanityTests(unittest.TestCase):
615617
with self.subTest(path=path):
616618
try:
617619
validator.validate(cases)
618-
except jsonschema.exceptions.RefResolutionError:
619-
# python-jsonschema/jsonschema#884
620-
pass
621620
except jsonschema.ValidationError as error:
622621
self.fail(str(error))
623622

bin/specification_urls.json

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"json-schema": {
3+
"draft2020-12": {
4+
"core": "https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-01#section-{section}",
5+
"validation": "https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-validation-01#section-{section}"
6+
},
7+
"draft2019-09": {
8+
"core": "https://json-schema.org/draft/2019-09/draft-handrews-json-schema-02#rfc.section.{section}",
9+
"validation": "https://json-schema.org/draft/2019-09/draft-handrews-json-schema-validation-02#rfc.section.{section}"
10+
},
11+
"draft7": {
12+
"core": "https://json-schema.org/draft-07/draft-handrews-json-schema-01#rfc.section.{section}",
13+
"validation": "https://json-schema.org/draft-07/draft-handrews-json-schema-validation-01#rfc.section.{section}"
14+
},
15+
"draft6": {
16+
"core": "https://json-schema.org/draft-06/draft-wright-json-schema-01#rfc.section.{section}",
17+
"validation": "https://json-schema.org/draft-06/draft-wright-json-schema-validation-01#rfc.section.{section}"
18+
},
19+
"draft4": {
20+
"core": "https://json-schema.org/draft-04/draft-zyp-json-schema-04#rfc.section.{section}",
21+
"validation": "https://json-schema.org/draft-04/draft-fge-json-schema-validation-00#rfc.section.{section}"
22+
},
23+
"draft3": {
24+
"core": "https://json-schema.org/draft-03/draft-zyp-json-schema-03.pdf"
25+
}
26+
},
27+
28+
"external": {
29+
"ecma262": "https://262.ecma-international.org/{section}",
30+
"perl5": "https://perldoc.perl.org/perlre#{section}",
31+
"rfc": "https://www.rfc-editor.org/rfc/{spec}.txt#{section}",
32+
"iso": "https://www.iso.org/obp/ui"
33+
}
34+
}

output-tests/draft2019-09/content/type.json

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,6 @@
3131
"required": ["errors"]
3232
}
3333
}
34-
},
35-
{
36-
"description": "correct type yields an output unit",
37-
"data": "a string",
38-
"output": {
39-
"basic": {
40-
"$id": "https://json-schema.org/tests/content/draft2019-09/type/0/tests/1/basic",
41-
"$ref": "/draft/2019-09/output/schema",
42-
"properties": {
43-
"annotations": {
44-
"contains": {
45-
"properties": {
46-
"valid": {"const": true},
47-
"keywordLocation": {"const": "/type"},
48-
"absoluteKeywordLocation": {"const": "https://json-schema.org/tests/content/draft2019-09/type/0#/type"},
49-
"instanceLocation": {"const": ""},
50-
"annotation": false,
51-
"error": false
52-
},
53-
"required": ["keywordLocation", "instanceLocation"]
54-
}
55-
}
56-
},
57-
"required": ["annotations"]
58-
}
59-
}
6034
}
6135
]
6236
}

output-tests/draft2020-12/content/type.json

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,32 +31,6 @@
3131
"required": ["errors"]
3232
}
3333
}
34-
},
35-
{
36-
"description": "correct type yields an output unit",
37-
"data": "a string",
38-
"output": {
39-
"basic": {
40-
"$id": "https://json-schema.org/tests/content/draft2020-12/type/0/tests/1/basic",
41-
"$ref": "/draft/2020-12/output/schema",
42-
"properties": {
43-
"annotations": {
44-
"contains": {
45-
"properties": {
46-
"valid": {"const": true},
47-
"keywordLocation": {"const": "/type"},
48-
"absoluteKeywordLocation": {"const": "https://json-schema.org/tests/content/draft2020-12/type/0#/type"},
49-
"instanceLocation": {"const": ""},
50-
"annotation": false,
51-
"error": false
52-
},
53-
"required": ["keywordLocation", "instanceLocation"]
54-
}
55-
}
56-
},
57-
"required": ["annotations"]
58-
}
59-
}
6034
}
6135
]
6236
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"$id": "http://localhost:1234/draft-next/detached-dynamicref.json",
3+
"$schema": "https://json-schema.org/draft/next/schema",
4+
"$defs": {
5+
"foo": {
6+
"$dynamicRef": "#detached"
7+
},
8+
"detached": {
9+
"$dynamicAnchor": "detached",
10+
"type": "integer"
11+
}
12+
}
13+
}

remotes/draft-next/detached-ref.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"$id": "http://localhost:1234/draft-next/detached-ref.json",
3+
"$schema": "https://json-schema.org/draft/next/schema",
4+
"$defs": {
5+
"foo": {
6+
"$ref": "#detached"
7+
},
8+
"detached": {
9+
"$anchor": "detached",
10+
"type": "integer"
11+
}
12+
}
13+
}

remotes/draft-next/format-assertion-false.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"https://json-schema.org/draft/next/vocab/core": true,
66
"https://json-schema.org/draft/next/vocab/format-assertion": false
77
},
8+
"$dynamicAnchor": "meta",
89
"allOf": [
910
{ "$ref": "https://json-schema.org/draft/next/meta/core" },
1011
{ "$ref": "https://json-schema.org/draft/next/meta/format-assertion" }

remotes/draft-next/format-assertion-true.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"https://json-schema.org/draft/next/vocab/core": true,
66
"https://json-schema.org/draft/next/vocab/format-assertion": true
77
},
8+
"$dynamicAnchor": "meta",
89
"allOf": [
910
{ "$ref": "https://json-schema.org/draft/next/meta/core" },
1011
{ "$ref": "https://json-schema.org/draft/next/meta/format-assertion" }

remotes/draft-next/metaschema-no-validation.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"https://json-schema.org/draft/next/vocab/applicator": true,
66
"https://json-schema.org/draft/next/vocab/core": true
77
},
8+
"$dynamicAnchor": "meta",
89
"allOf": [
910
{ "$ref": "https://json-schema.org/draft/next/meta/applicator" },
1011
{ "$ref": "https://json-schema.org/draft/next/meta/core" }

0 commit comments

Comments
 (0)