Skip to content

Commit c7a0f3e

Browse files
committed
Reconcile terminology in the sanity checker with the README
(A lot of what's here is minor Python modernization, this was written awhile ago...) But the main "useful" thing is to reconcile the language in the implementation here with what's in the README now: https://github.com/json-schema-org/JSON-Schema-Test-Suite#terminology i.e.: files -> files groups -> cases cases -> tests
1 parent 1e0ebd2 commit c7a0f3e

File tree

1 file changed

+73
-62
lines changed

1 file changed

+73
-62
lines changed

bin/jsonschema_suite

Lines changed: 73 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#! /usr/bin/env python3
2+
from pathlib import Path
23
import argparse
34
import errno
4-
import fnmatch
55
import json
66
import os
77
import random
@@ -28,119 +28,133 @@ else:
2828
}
2929

3030

31-
ROOT_DIR = os.path.abspath(
32-
os.path.join(os.path.dirname(__file__), os.pardir).rstrip("__pycache__"),
33-
)
34-
SUITE_ROOT_DIR = os.path.join(ROOT_DIR, "tests")
35-
REMOTES_DIR = os.path.join(ROOT_DIR, "remotes")
36-
31+
ROOT_DIR = Path(__file__).parent.parent
32+
SUITE_ROOT_DIR = ROOT_DIR / "tests"
33+
REMOTES_DIR = ROOT_DIR / "remotes"
3734

38-
with open(os.path.join(ROOT_DIR, "test-schema.json")) as schema:
39-
TESTSUITE_SCHEMA = json.load(schema)
35+
TESTSUITE_SCHEMA = json.loads((ROOT_DIR / "test-schema.json").read_text())
4036

4137

4238
def files(paths):
4339
"""
44-
Each test file in the provided paths.
40+
Each test file in the provided paths, as an array of test cases.
4541
"""
4642
for path in paths:
47-
with open(path) as test_file:
48-
yield json.load(test_file)
43+
yield json.loads(path.read_text())
4944

5045

51-
def groups(paths):
46+
def cases(paths):
5247
"""
53-
Each test group within each file in the provided paths.
48+
Each test case within each file in the provided paths.
5449
"""
5550
for test_file in files(paths):
56-
for group in test_file:
57-
yield group
51+
yield from test_file
5852

5953

60-
def cases(paths):
54+
def tests(paths):
6155
"""
62-
Each individual test case within all groups within the provided paths.
56+
Each individual test within all cases within the provided paths.
6357
"""
64-
for test_group in groups(paths):
65-
for test in test_group["tests"]:
66-
test["schema"] = test_group["schema"]
58+
for case in cases(paths):
59+
for test in case["tests"]:
60+
test["schema"] = case["schema"]
6761
yield test
6862

6963

7064
def collect(root_dir):
7165
"""
7266
All of the test file paths within the given root directory, recursively.
7367
"""
74-
for root, _, files in os.walk(root_dir):
75-
for filename in fnmatch.filter(files, "*.json"):
76-
yield os.path.join(root, filename)
68+
return root_dir.glob("**/*.json")
7769

7870

7971
class SanityTests(unittest.TestCase):
8072
@classmethod
8173
def setUpClass(cls):
82-
print("Looking for tests in %s" % SUITE_ROOT_DIR)
83-
print("Looking for remotes in %s" % REMOTES_DIR)
74+
print(f"Looking for tests in {SUITE_ROOT_DIR}")
75+
print(f"Looking for remotes in {REMOTES_DIR}")
76+
8477
cls.test_files = list(collect(SUITE_ROOT_DIR))
85-
cls.remote_files = list(collect(REMOTES_DIR))
86-
print("Found %s test files" % len(cls.test_files))
87-
print("Found %s remote files" % len(cls.remote_files))
8878
assert cls.test_files, "Didn't find the test files!"
79+
print(f"Found {len(cls.test_files)} test files")
80+
81+
cls.remote_files = list(collect(REMOTES_DIR))
8982
assert cls.remote_files, "Didn't find the remote files!"
83+
print(f"Found {len(cls.remote_files)} remote files")
9084

9185
def test_all_test_files_are_valid_json(self):
86+
"""
87+
All test files contain valid JSON.
88+
"""
9289
for path in self.test_files:
93-
with open(path) as test_file:
94-
try:
95-
json.load(test_file)
96-
except ValueError as error:
97-
self.fail("%s contains invalid JSON (%s)" % (path, error))
90+
try:
91+
json.loads(path.read_text())
92+
except ValueError as error:
93+
self.fail(f"{path} contains invalid JSON ({error})")
9894

9995
def test_all_remote_files_are_valid_json(self):
96+
"""
97+
All remote files contain valid JSON.
98+
"""
10099
for path in self.remote_files:
101-
with open(path) as remote_file:
102-
try:
103-
json.load(remote_file)
104-
except ValueError as error:
105-
self.fail("%s contains invalid JSON (%s)" % (path, error))
100+
try:
101+
json.loads(path.read_text())
102+
except ValueError as error:
103+
self.fail(f"{path} contains invalid JSON ({error})")
106104

107105
def test_all_descriptions_have_reasonable_length(self):
108-
for case in cases(self.test_files):
109-
description = case["description"]
106+
"""
107+
All tests have reasonably long descriptions.
108+
"""
109+
for count, test in enumerate(tests(self.test_files)):
110+
description = test["description"]
110111
self.assertLess(
111112
len(description),
112113
70,
113-
"%r is too long! (keep it to less than 70 chars)" % (
114-
description,
115-
),
114+
f"{description!r} is too long! (keep it to less than 70 chars)"
116115
)
116+
print(f"Found {count} tests.")
117117

118118
def test_all_descriptions_are_unique(self):
119-
for group in groups(self.test_files):
120-
descriptions = set(test["description"] for test in group["tests"])
119+
"""
120+
All test cases have unique test descriptions in their tests.
121+
"""
122+
for count, case in enumerate(cases(self.test_files)):
123+
descriptions = set(test["description"] for test in case["tests"])
121124
self.assertEqual(
122125
len(descriptions),
123-
len(group["tests"]),
124-
"%r contains a duplicate description" % (group,)
126+
len(case["tests"]),
127+
f"{case!r} contains a duplicate description",
125128
)
129+
print(f"Found {count} test cases.")
126130

127131
@unittest.skipIf(jsonschema is None, "Validation library not present!")
128132
def test_all_schemas_are_valid(self):
129-
for version in os.listdir(SUITE_ROOT_DIR):
130-
Validator = VALIDATORS.get(version)
133+
"""
134+
All schemas are valid under their metaschemas.
135+
"""
136+
for version in SUITE_ROOT_DIR.iterdir():
137+
if not version.is_dir():
138+
continue
139+
140+
Validator = VALIDATORS.get(version.name)
131141
if Validator is not None:
132-
test_files = collect(os.path.join(SUITE_ROOT_DIR, version))
142+
test_files = collect(version)
133143
for case in cases(test_files):
134144
try:
135145
Validator.check_schema(case["schema"])
136146
except jsonschema.SchemaError as error:
137-
self.fail("%s contains an invalid schema (%s)" %
138-
(case, error))
147+
self.fail(
148+
f"{case} contains an invalid schema ({error})",
149+
)
139150
else:
140-
warnings.warn("No schema validator for %s" % schema)
151+
warnings.warn(f"No schema validator for {version.name}")
141152

142153
@unittest.skipIf(jsonschema is None, "Validation library not present!")
143154
def test_suites_are_valid(self):
155+
"""
156+
All test files are valid under test-schema.json.
157+
"""
144158
Validator = jsonschema.validators.validator_for(TESTSUITE_SCHEMA)
145159
validator = Validator(TESTSUITE_SCHEMA)
146160
for tests in files(self.test_files):
@@ -153,7 +167,7 @@ class SanityTests(unittest.TestCase):
153167
def main(arguments):
154168
if arguments.command == "check":
155169
suite = unittest.TestLoader().loadTestsFromTestCase(SanityTests)
156-
result = unittest.TextTestRunner(verbosity=2).run(suite)
170+
result = unittest.TextTestRunner().run(suite)
157171
sys.exit(not result.wasSuccessful())
158172
elif arguments.command == "flatten":
159173
selected_cases = [case for case in cases(collect(arguments.version))]
@@ -166,20 +180,17 @@ def main(arguments):
166180
remotes = {}
167181
for path in collect(REMOTES_DIR):
168182
relative_path = os.path.relpath(path, REMOTES_DIR)
169-
with open(path) as schema_file:
170-
remotes[relative_path] = json.load(schema_file)
183+
remotes[relative_path] = json.loads(path.read_text())
171184
json.dump(remotes, sys.stdout, indent=4, sort_keys=True)
172185
elif arguments.command == "dump_remotes":
173186
if arguments.update:
174187
shutil.rmtree(arguments.out_dir, ignore_errors=True)
175188

176189
try:
177190
shutil.copytree(REMOTES_DIR, arguments.out_dir)
178-
except OSError as e:
179-
if e.errno == errno.EEXIST:
180-
print("%s already exists. Aborting." % arguments.out_dir)
181-
sys.exit(1)
182-
raise
191+
except FileExistsError:
192+
print(f"{arguments.out_dir} already exists. Aborting.")
193+
sys.exit(1)
183194
elif arguments.command == "serve":
184195
try:
185196
import flask

0 commit comments

Comments
 (0)