-
-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* develop: (105 commits) Port to draft4. Fixed incorrect negative description of a sub test Minor shuffling. updated node.js info in README.md Add the README note on develop. JavaScript should written in upper camel case added ajv validator to readme Add another Go implementation Update pattern.json Update ref.json Add valid instances for escaped ref tests Add a test that checks for implicit anchoring Add jsen to the list of validators Use tox to run tests Add test case for protocol-relative uri validation [README] JSONSchema.swift uses these tests too Revert "Add jon, JSON parser for the fishshell." Add jon, JSON parser for the fishshell. Add new Rust library to the list Add new haskell implementation. Add json-schema-benchmark to list of users of this test suite Added Newtonsoft.Json.Schema implementation Added skeemas to list of suite users Make the implementation list a bit less unwieldy now that it's so long (hooray!) Add request-validator as a user of the test suite Update README.md Add tests for additionalProperties by itself. Added tests around the default property Added the json-schema ruby gem to the list of libraries using the test suite Applies to Draft4 as well. Check comparisons for very negative numbers as well. jsck uses JSON Schema Test Suite fixed maxLength test case Add a test for large int comparisons. Add a note to the README about running sanity checks. Shorten the descriptions slightly. Add string length tests for supplementary Unicode code points As per the spec, only dotted-quad is an acceptable format for IPv4 addresses. add json-schema-valid to list of validators add 'forbidden property' test (not with blank schema) Add the enum/required test to draft4 too Add tests for required/not required values with enums Add Jsonary and tv4 to the list Added Jassi library to the list. Add a test for valid URI reference, but invalid URI (which is not valid overall). patternProperties are not additionalProperties in draft3 either. add test to draft4 that checks that patternProperties are not counted as additionalProperties added entry for Dart Added z-schema to the list Update README.md ...
- Loading branch information
Showing
61 changed files
with
3,419 additions
and
193 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
language: python | ||
python: "2.7" | ||
install: pip install jsonschema | ||
script: bin/suite_sanity_check -v | ||
install: pip install tox | ||
script: tox |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,283 @@ | ||
#! /usr/bin/env python | ||
from __future__ import print_function | ||
import sys | ||
import textwrap | ||
|
||
try: | ||
import argparse | ||
except ImportError: | ||
print(textwrap.dedent(""" | ||
The argparse library could not be imported. jsonschema_suite requires | ||
either Python 2.7 or for you to install argparse. You can do so by | ||
running `pip install argparse`, `easy_install argparse` or by | ||
downloading argparse and running `python2.6 setup.py install`. | ||
See https://pypi.python.org/pypi/argparse for details. | ||
""".strip("\n"))) | ||
sys.exit(1) | ||
|
||
import errno | ||
import fnmatch | ||
import json | ||
import os | ||
import random | ||
import shutil | ||
import unittest | ||
import warnings | ||
|
||
if getattr(unittest, "skipIf", None) is None: | ||
unittest.skipIf = lambda cond, msg : lambda fn : fn | ||
|
||
try: | ||
import jsonschema | ||
except ImportError: | ||
jsonschema = None | ||
else: | ||
validators = getattr( | ||
jsonschema.validators, "validators", jsonschema.validators | ||
) | ||
|
||
|
||
ROOT_DIR = os.path.join( | ||
os.path.dirname(__file__), os.pardir).rstrip("__pycache__") | ||
SUITE_ROOT_DIR = os.path.join(ROOT_DIR, "tests") | ||
|
||
REMOTES = { | ||
"integer.json": {"type": "integer"}, | ||
"subSchemas.json": { | ||
"integer": {"type": "integer"}, | ||
"refToInteger": {"$ref": "#/integer"}, | ||
}, | ||
"folder/folderInteger.json": {"type": "integer"} | ||
} | ||
REMOTES_DIR = os.path.join(ROOT_DIR, "remotes") | ||
|
||
TESTSUITE_SCHEMA = { | ||
"$schema": "http://json-schema.org/draft-03/schema#", | ||
"type": "array", | ||
"items": { | ||
"type": "object", | ||
"properties": { | ||
"description": {"type": "string", "required": True}, | ||
"schema": {"required": True}, | ||
"tests": { | ||
"type": "array", | ||
"items": { | ||
"type": "object", | ||
"properties": { | ||
"description": {"type": "string", "required": True}, | ||
"data": {"required": True}, | ||
"valid": {"type": "boolean", "required": True} | ||
}, | ||
"additionalProperties": False | ||
}, | ||
"minItems": 1 | ||
} | ||
}, | ||
"additionalProperties": False, | ||
"minItems": 1 | ||
} | ||
} | ||
|
||
|
||
def files(paths): | ||
for path in paths: | ||
with open(path) as test_file: | ||
yield json.load(test_file) | ||
|
||
|
||
def groups(paths): | ||
for test_file in files(paths): | ||
for group in test_file: | ||
yield group | ||
|
||
|
||
def cases(paths): | ||
for test_group in groups(paths): | ||
for test in test_group["tests"]: | ||
test["schema"] = test_group["schema"] | ||
yield test | ||
|
||
|
||
def collect(root_dir): | ||
for root, dirs, files in os.walk(root_dir): | ||
for filename in fnmatch.filter(files, "*.json"): | ||
yield os.path.join(root, filename) | ||
|
||
|
||
class SanityTests(unittest.TestCase): | ||
@classmethod | ||
def setUpClass(cls): | ||
print("Looking for tests in %s" % SUITE_ROOT_DIR) | ||
cls.test_files = list(collect(SUITE_ROOT_DIR)) | ||
print("Found %s test files" % len(cls.test_files)) | ||
assert cls.test_files, "Didn't find the test files!" | ||
|
||
def test_all_files_are_valid_json(self): | ||
for path in self.test_files: | ||
with open(path) as test_file: | ||
try: | ||
json.load(test_file) | ||
except ValueError as error: | ||
self.fail("%s contains invalid JSON (%s)" % (path, error)) | ||
|
||
def test_all_descriptions_have_reasonable_length(self): | ||
for case in cases(self.test_files): | ||
descript = case["description"] | ||
self.assertLess( | ||
len(descript), | ||
60, | ||
"%r is too long! (keep it to less than 60 chars)" % (descript,) | ||
) | ||
|
||
def test_all_descriptions_are_unique(self): | ||
for group in groups(self.test_files): | ||
descriptions = set(test["description"] for test in group["tests"]) | ||
self.assertEqual( | ||
len(descriptions), | ||
len(group["tests"]), | ||
"%r contains a duplicate description" % (group,) | ||
) | ||
|
||
@unittest.skipIf(jsonschema is None, "Validation library not present!") | ||
def test_all_schemas_are_valid(self): | ||
for schema in os.listdir(SUITE_ROOT_DIR): | ||
schema_validator = validators.get(schema) | ||
if schema_validator is not None: | ||
test_files = collect(os.path.join(SUITE_ROOT_DIR, schema)) | ||
for case in cases(test_files): | ||
try: | ||
schema_validator.check_schema(case["schema"]) | ||
except jsonschema.SchemaError as error: | ||
self.fail("%s contains an invalid schema (%s)" % | ||
(case, error)) | ||
else: | ||
warnings.warn("No schema validator for %s" % schema) | ||
|
||
@unittest.skipIf(jsonschema is None, "Validation library not present!") | ||
def test_suites_are_valid(self): | ||
validator = jsonschema.Draft3Validator(TESTSUITE_SCHEMA) | ||
for tests in files(self.test_files): | ||
try: | ||
validator.validate(tests) | ||
except jsonschema.ValidationError as error: | ||
self.fail(str(error)) | ||
|
||
def test_remote_schemas_are_updated(self): | ||
for url, schema in REMOTES.items(): | ||
filepath = os.path.join(REMOTES_DIR, url) | ||
with open(filepath) as schema_file: | ||
self.assertEqual(json.load(schema_file), schema) | ||
|
||
|
||
def main(arguments): | ||
if arguments.command == "check": | ||
suite = unittest.TestLoader().loadTestsFromTestCase(SanityTests) | ||
result = unittest.TextTestRunner(verbosity=2).run(suite) | ||
sys.exit(not result.wasSuccessful()) | ||
elif arguments.command == "flatten": | ||
selected_cases = [case for case in cases(collect(arguments.version))] | ||
|
||
if arguments.randomize: | ||
random.shuffle(selected_cases) | ||
|
||
json.dump(selected_cases, sys.stdout, indent=4, sort_keys=True) | ||
elif arguments.command == "remotes": | ||
json.dump(REMOTES, sys.stdout, indent=4, sort_keys=True) | ||
elif arguments.command == "dump_remotes": | ||
if arguments.update: | ||
shutil.rmtree(arguments.out_dir, ignore_errors=True) | ||
|
||
try: | ||
os.makedirs(arguments.out_dir) | ||
except OSError as e: | ||
if e.errno == errno.EEXIST: | ||
print("%s already exists. Aborting." % arguments.out_dir) | ||
sys.exit(1) | ||
raise | ||
|
||
for url, schema in REMOTES.items(): | ||
filepath = os.path.join(arguments.out_dir, url) | ||
|
||
try: | ||
os.makedirs(os.path.dirname(filepath)) | ||
except OSError as e: | ||
if e.errno != errno.EEXIST: | ||
raise | ||
|
||
with open(filepath, "wb") as out_file: | ||
json.dump(schema, out_file, indent=4, sort_keys=True) | ||
elif arguments.command == "serve": | ||
try: | ||
from flask import Flask, jsonify | ||
except ImportError: | ||
print(textwrap.dedent(""" | ||
The Flask library is required to serve the remote schemas. | ||
You can install it by running `pip install Flask`. | ||
Alternatively, see the `jsonschema_suite remotes` or | ||
`jsonschema_suite dump_remotes` commands to create static files | ||
that can be served with your own web server. | ||
""".strip("\n"))) | ||
sys.exit(1) | ||
|
||
app = Flask(__name__) | ||
|
||
@app.route("/<path:path>") | ||
def serve_path(path): | ||
if path in REMOTES: | ||
return jsonify(REMOTES[path]) | ||
return "Document does not exist.", 404 | ||
|
||
app.run(port=1234) | ||
|
||
|
||
parser = argparse.ArgumentParser( | ||
description="JSON Schema Test Suite utilities", | ||
) | ||
subparsers = parser.add_subparsers(help="utility commands", dest="command") | ||
|
||
check = subparsers.add_parser("check", help="Sanity check the test suite.") | ||
|
||
flatten = subparsers.add_parser( | ||
"flatten", | ||
help="Output a flattened file containing a selected version's test cases." | ||
) | ||
flatten.add_argument( | ||
"--randomize", | ||
action="store_true", | ||
help="Randomize the order of the outputted cases.", | ||
) | ||
flatten.add_argument( | ||
"version", help="The directory containing the version to output", | ||
) | ||
|
||
remotes = subparsers.add_parser( | ||
"remotes", | ||
help="Output the expected URLs and their associated schemas for remote " | ||
"ref tests as a JSON object." | ||
) | ||
|
||
dump_remotes = subparsers.add_parser( | ||
"dump_remotes", help="Dump the remote ref schemas into a file tree", | ||
) | ||
dump_remotes.add_argument( | ||
"--update", | ||
action="store_true", | ||
help="Update the remotes in an existing directory.", | ||
) | ||
dump_remotes.add_argument( | ||
"--out-dir", | ||
default=REMOTES_DIR, | ||
type=os.path.abspath, | ||
help="The output directory to create as the root of the file tree", | ||
) | ||
|
||
serve = subparsers.add_parser( | ||
"serve", | ||
help="Start a webserver to serve schemas used by remote ref tests." | ||
) | ||
|
||
if __name__ == "__main__": | ||
main(parser.parse_args()) |
Oops, something went wrong.