summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--jsonschema/tests/__init__.py0
-rw-r--r--jsonschema/tests/compat.py15
-rw-r--r--jsonschema/tests/test_format.py58
-rw-r--r--jsonschema/tests/test_jsonschema_test_suite.py236
-rw-r--r--jsonschema/tests/test_validators.py (renamed from test_jsonschema.py)302
-rw-r--r--tox.ini5
6 files changed, 316 insertions, 300 deletions
diff --git a/jsonschema/tests/__init__.py b/jsonschema/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/jsonschema/tests/__init__.py
diff --git a/jsonschema/tests/compat.py b/jsonschema/tests/compat.py
new file mode 100644
index 0000000..b37483f
--- /dev/null
+++ b/jsonschema/tests/compat.py
@@ -0,0 +1,15 @@
+import sys
+
+
+if sys.version_info[:2] < (2, 7): # pragma: no cover
+ import unittest2 as unittest
+else:
+ import unittest
+
+try:
+ from unittest import mock
+except ImportError:
+ import mock
+
+
+# flake8: noqa
diff --git a/jsonschema/tests/test_format.py b/jsonschema/tests/test_format.py
new file mode 100644
index 0000000..e7576b4
--- /dev/null
+++ b/jsonschema/tests/test_format.py
@@ -0,0 +1,58 @@
+from jsonschema.tests.compat import mock, unittest
+
+from jsonschema import FormatError, ValidationError, FormatChecker
+from jsonschema.validators import Draft4Validator
+
+
+class TestFormatChecker(unittest.TestCase):
+ def setUp(self):
+ self.fn = mock.Mock()
+
+ def test_it_can_validate_no_formats(self):
+ checker = FormatChecker(formats=())
+ self.assertFalse(checker.checkers)
+
+ def test_it_raises_a_key_error_for_unknown_formats(self):
+ with self.assertRaises(KeyError):
+ FormatChecker(formats=["o noes"])
+
+ def test_it_can_register_cls_checkers(self):
+ with mock.patch.dict(FormatChecker.checkers, clear=True):
+ FormatChecker.cls_checks("new")(self.fn)
+ self.assertEqual(FormatChecker.checkers, {"new" : (self.fn, ())})
+
+ def test_it_can_register_checkers(self):
+ checker = FormatChecker()
+ checker.checks("new")(self.fn)
+ self.assertEqual(
+ checker.checkers,
+ dict(FormatChecker.checkers, new=(self.fn, ()))
+ )
+
+ def test_it_catches_registered_errors(self):
+ checker = FormatChecker()
+ cause = self.fn.side_effect = ValueError()
+
+ checker.checks("foo", raises=ValueError)(self.fn)
+
+ with self.assertRaises(FormatError) as cm:
+ checker.check("bar", "foo")
+
+ self.assertIs(cm.exception.cause, cause)
+ self.assertIs(cm.exception.__cause__, cause)
+
+ # Unregistered errors should not be caught
+ self.fn.side_effect = AttributeError
+ with self.assertRaises(AttributeError):
+ checker.check("bar", "foo")
+
+ def test_format_error_causes_become_validation_error_causes(self):
+ checker = FormatChecker()
+ checker.checks("foo", raises=ValueError)(self.fn)
+ cause = self.fn.side_effect = ValueError()
+ validator = Draft4Validator({"format" : "foo"}, format_checker=checker)
+
+ with self.assertRaises(ValidationError) as cm:
+ validator.validate("bar")
+
+ self.assertIs(cm.exception.__cause__, cause)
diff --git a/jsonschema/tests/test_jsonschema_test_suite.py b/jsonschema/tests/test_jsonschema_test_suite.py
new file mode 100644
index 0000000..b9c3c95
--- /dev/null
+++ b/jsonschema/tests/test_jsonschema_test_suite.py
@@ -0,0 +1,236 @@
+from decimal import Decimal
+import glob
+import json
+import io
+import itertools
+import os
+import re
+import subprocess
+
+try:
+ from sys import pypy_version_info
+except ImportError:
+ pypy_version_info = None
+
+from jsonschema import (
+ FormatError, SchemaError, ValidationError, Draft3Validator,
+ Draft4Validator, FormatChecker, draft3_format_checker,
+ draft4_format_checker, validate,
+)
+from jsonschema.compat import PY3
+from jsonschema.tests.compat import mock, unittest
+import jsonschema
+
+
+REPO_ROOT = os.path.join(os.path.dirname(jsonschema.__file__), os.path.pardir)
+SUITE = os.getenv("JSON_SCHEMA_TEST_SUITE", os.path.join(REPO_ROOT, "json"))
+
+if not os.path.isdir(SUITE):
+ raise ValueError(
+ "Can't find the JSON-Schema-Test-Suite directory. Set the "
+ "'JSON_SCHEMA_TEST_SUITE' environment variable or run the tests from "
+ "alongside a checkout of the suite."
+ )
+
+TESTS_DIR = os.path.join(SUITE, "tests")
+JSONSCHEMA_SUITE = os.path.join(SUITE, "bin", "jsonschema_suite")
+
+REMOTES = subprocess.Popen(
+ ["python", JSONSCHEMA_SUITE, "remotes"], stdout=subprocess.PIPE,
+).stdout
+if PY3:
+ REMOTES = io.TextIOWrapper(REMOTES)
+REMOTES = json.load(REMOTES)
+
+
+def make_case(schema, data, valid):
+ if valid:
+ def test_case(self):
+ kwargs = getattr(self, "validator_kwargs", {})
+ validate(data, schema, cls=self.validator_class, **kwargs)
+ else:
+ def test_case(self):
+ kwargs = getattr(self, "validator_kwargs", {})
+ with self.assertRaises(ValidationError):
+ validate(data, schema, cls=self.validator_class, **kwargs)
+ return test_case
+
+
+def load_json_cases(tests_glob, ignore_glob="", basedir=TESTS_DIR, skip=None):
+ if ignore_glob:
+ ignore_glob = os.path.join(basedir, ignore_glob)
+
+ def add_test_methods(test_class):
+ ignored = set(glob.iglob(ignore_glob))
+
+ for filename in glob.iglob(os.path.join(basedir, tests_glob)):
+ if filename in ignored:
+ continue
+
+ validating, _ = os.path.splitext(os.path.basename(filename))
+ id = itertools.count(1)
+
+ with open(filename) as test_file:
+ data = json.load(test_file)
+
+ for case in data:
+ for test in case["tests"]:
+ a_test = make_case(
+ case["schema"],
+ test["data"],
+ test["valid"],
+ )
+
+ test_name = "test_%s_%s_%s" % (
+ validating,
+ next(id),
+ re.sub(r"[\W ]+", "_", test["description"]),
+ )
+
+ if not PY3:
+ test_name = test_name.encode("utf-8")
+ a_test.__name__ = test_name
+
+ if skip is not None and skip(case):
+ a_test = unittest.skip("Checker not present.")(
+ a_test
+ )
+
+ assert not hasattr(test_class, test_name), test_name
+ setattr(test_class, test_name, a_test)
+
+ return test_class
+ return add_test_methods
+
+
+class TypesMixin(object):
+ @unittest.skipIf(PY3, "In Python 3 json.load always produces unicode")
+ def test_string_a_bytestring_is_a_string(self):
+ self.validator_class({"type" : "string"}).validate(b"foo")
+
+
+class DecimalMixin(object):
+ def test_it_can_validate_with_decimals(self):
+ schema = {"type" : "number"}
+ validator = self.validator_class(
+ schema, types={"number" : (int, float, Decimal)}
+ )
+
+ for valid in [1, 1.1, Decimal(1) / Decimal(8)]:
+ validator.validate(valid)
+
+ for invalid in ["foo", {}, [], True, None]:
+ with self.assertRaises(ValidationError):
+ validator.validate(invalid)
+
+
+def missing_format(checker):
+ def missing_format(case):
+ format = case["schema"].get("format")
+ return format not in checker.checkers or (
+ # datetime.datetime is overzealous about typechecking in <=1.9
+ format == "date-time" and
+ pypy_version_info is not None and
+ pypy_version_info[:2] <= (1, 9)
+ )
+ return missing_format
+
+
+class FormatMixin(object):
+ def test_it_returns_true_for_formats_it_does_not_know_about(self):
+ validator = self.validator_class(
+ {"format" : "carrot"}, format_checker=FormatChecker(),
+ )
+ validator.validate("bugs")
+
+ def test_it_does_not_validate_formats_by_default(self):
+ validator = self.validator_class({})
+ self.assertIsNone(validator.format_checker)
+
+ def test_it_validates_formats_if_a_checker_is_provided(self):
+ checker = mock.Mock(spec=FormatChecker)
+ validator = self.validator_class(
+ {"format" : "foo"}, format_checker=checker,
+ )
+
+ validator.validate("bar")
+
+ checker.check.assert_called_once_with("bar", "foo")
+
+ cause = ValueError()
+ checker.check.side_effect = FormatError('aoeu', cause=cause)
+
+ with self.assertRaises(ValidationError) as cm:
+ validator.validate("bar")
+ # Make sure original cause is attached
+ self.assertIs(cm.exception.cause, cause)
+
+
+@load_json_cases("draft3/*.json", ignore_glob="draft3/refRemote.json")
+@load_json_cases(
+ "draft3/optional/format.json", skip=missing_format(draft3_format_checker)
+)
+@load_json_cases("draft3/optional/bignum.json")
+@load_json_cases("draft3/optional/zeroTerminatedFloats.json")
+class TestDraft3(unittest.TestCase, TypesMixin, DecimalMixin, FormatMixin):
+ validator_class = Draft3Validator
+ validator_kwargs = {"format_checker" : draft3_format_checker}
+
+ def test_any_type_is_valid_for_type_any(self):
+ validator = self.validator_class({"type" : "any"})
+ validator.validate(mock.Mock())
+
+ # TODO: we're in need of more meta schema tests
+ def test_invalid_properties(self):
+ with self.assertRaises(SchemaError):
+ validate({}, {"properties": {"test": True}},
+ cls=self.validator_class)
+
+ def test_minItems_invalid_string(self):
+ with self.assertRaises(SchemaError):
+ # needs to be an integer
+ validate([1], {"minItems" : "1"}, cls=self.validator_class)
+
+
+@load_json_cases("draft4/*.json", ignore_glob="draft4/refRemote.json")
+@load_json_cases(
+ "draft4/optional/format.json", skip=missing_format(draft4_format_checker)
+)
+@load_json_cases("draft4/optional/bignum.json")
+@load_json_cases("draft4/optional/zeroTerminatedFloats.json")
+class TestDraft4(unittest.TestCase, TypesMixin, DecimalMixin, FormatMixin):
+ validator_class = Draft4Validator
+ validator_kwargs = {"format_checker" : draft4_format_checker}
+
+ # TODO: we're in need of more meta schema tests
+ def test_invalid_properties(self):
+ with self.assertRaises(SchemaError):
+ validate({}, {"properties": {"test": True}},
+ cls=self.validator_class)
+
+ def test_minItems_invalid_string(self):
+ with self.assertRaises(SchemaError):
+ # needs to be an integer
+ validate([1], {"minItems" : "1"}, cls=self.validator_class)
+
+
+class RemoteRefResolutionMixin(object):
+ def setUp(self):
+ patch = mock.patch("jsonschema.validators.requests")
+ requests = patch.start()
+ requests.get.side_effect = self.resolve
+ self.addCleanup(patch.stop)
+
+ def resolve(self, reference):
+ _, _, reference = reference.partition("http://localhost:1234/")
+ return mock.Mock(**{"json.return_value" : REMOTES.get(reference)})
+
+
+@load_json_cases("draft3/refRemote.json")
+class Draft3RemoteResolution(RemoteRefResolutionMixin, unittest.TestCase):
+ validator_class = Draft3Validator
+
+
+@load_json_cases("draft4/refRemote.json")
+class Draft4RemoteResolution(RemoteRefResolutionMixin, unittest.TestCase):
+ validator_class = Draft4Validator
diff --git a/test_jsonschema.py b/jsonschema/tests/test_validators.py
index 7a07904..2fd1d91 100644
--- a/test_jsonschema.py
+++ b/jsonschema/tests/test_validators.py
@@ -1,254 +1,16 @@
from __future__ import unicode_literals
-from decimal import Decimal
import contextlib
-import glob
-import io
-import itertools
import json
-import os
import pprint
-import re
-import subprocess
-import sys
import textwrap
-if sys.version_info[:2] < (2, 7): # pragma: no cover
- import unittest2 as unittest
-else:
- import unittest
-
-try:
- from unittest import mock
-except ImportError:
- import mock
-
-try:
- from sys import pypy_version_info
-except ImportError:
- pypy_version_info = None
-
-from jsonschema import (
- FormatError, RefResolutionError, SchemaError, UnknownType,
- ValidationError, ErrorTree, Draft3Validator, Draft4Validator,
- FormatChecker, RefResolver, ValidatorMixin, draft3_format_checker,
- draft4_format_checker, validate,
-)
+from jsonschema import FormatChecker
from jsonschema.compat import PY3
-
-
-THIS_DIR = os.path.dirname(__file__)
-TESTS_DIR = os.path.join(THIS_DIR, "json", "tests")
-
-JSONSCHEMA_SUITE = os.path.join(THIS_DIR, "json", "bin", "jsonschema_suite")
-
-REMOTES = subprocess.Popen(
- ["python", JSONSCHEMA_SUITE, "remotes"], stdout=subprocess.PIPE,
-).stdout
-if PY3:
- REMOTES = io.TextIOWrapper(REMOTES)
-REMOTES = json.load(REMOTES)
-
-
-def make_case(schema, data, valid):
- if valid:
- def test_case(self):
- kwargs = getattr(self, "validator_kwargs", {})
- validate(data, schema, cls=self.validator_class, **kwargs)
- else:
- def test_case(self):
- kwargs = getattr(self, "validator_kwargs", {})
- with self.assertRaises(ValidationError):
- validate(data, schema, cls=self.validator_class, **kwargs)
- return test_case
-
-
-def load_json_cases(tests_glob, ignore_glob="", basedir=TESTS_DIR, skip=None):
- if ignore_glob:
- ignore_glob = os.path.join(basedir, ignore_glob)
-
- def add_test_methods(test_class):
- ignored = set(glob.iglob(ignore_glob))
-
- for filename in glob.iglob(os.path.join(basedir, tests_glob)):
- if filename in ignored:
- continue
-
- validating, _ = os.path.splitext(os.path.basename(filename))
- id = itertools.count(1)
-
- with open(filename) as test_file:
- data = json.load(test_file)
-
- for case in data:
- for test in case["tests"]:
- a_test = make_case(
- case["schema"],
- test["data"],
- test["valid"],
- )
-
- test_name = "test_%s_%s_%s" % (
- validating,
- next(id),
- re.sub(r"[\W ]+", "_", test["description"]),
- )
-
- if not PY3:
- test_name = test_name.encode("utf-8")
- a_test.__name__ = test_name
-
- if skip is not None and skip(case):
- a_test = unittest.skip("Checker not present.")(
- a_test
- )
-
- assert not hasattr(test_class, test_name), test_name
- setattr(test_class, test_name, a_test)
-
- return test_class
- return add_test_methods
-
-
-class TypesMixin(object):
- @unittest.skipIf(PY3, "In Python 3 json.load always produces unicode")
- def test_string_a_bytestring_is_a_string(self):
- self.validator_class({"type" : "string"}).validate(b"foo")
-
-
-class DecimalMixin(object):
- def test_it_can_validate_with_decimals(self):
- schema = {"type" : "number"}
- validator = self.validator_class(
- schema, types={"number" : (int, float, Decimal)}
- )
-
- for valid in [1, 1.1, Decimal(1) / Decimal(8)]:
- validator.validate(valid)
-
- for invalid in ["foo", {}, [], True, None]:
- with self.assertRaises(ValidationError):
- validator.validate(invalid)
-
-
-def missing_format(checker):
- def missing_format(case):
- format = case["schema"].get("format")
- return format not in checker.checkers or (
- # datetime.datetime is overzealous about typechecking in <=1.9
- format == "date-time" and
- pypy_version_info is not None and
- pypy_version_info[:2] <= (1, 9)
- )
- return missing_format
-
-
-class FormatMixin(object):
- def test_it_returns_true_for_formats_it_does_not_know_about(self):
- validator = self.validator_class(
- {"format" : "carrot"}, format_checker=FormatChecker(),
- )
- validator.validate("bugs")
-
- def test_it_does_not_validate_formats_by_default(self):
- validator = self.validator_class({})
- self.assertIsNone(validator.format_checker)
-
- def test_it_validates_formats_if_a_checker_is_provided(self):
- checker = mock.Mock(spec=FormatChecker)
- validator = self.validator_class(
- {"format" : "foo"}, format_checker=checker,
- )
-
- validator.validate("bar")
-
- checker.check.assert_called_once_with("bar", "foo")
-
- cause = ValueError()
- checker.check.side_effect = FormatError('aoeu', cause=cause)
-
- with self.assertRaises(ValidationError) as cm:
- validator.validate("bar")
- # Make sure original cause is attached
- self.assertIs(cm.exception.cause, cause)
-
-
-@load_json_cases(
- "draft3/*.json", ignore_glob=os.path.join("draft3", "refRemote.json")
-)
-@load_json_cases(
- "draft3/optional/format.json", skip=missing_format(draft3_format_checker)
-)
-@load_json_cases("draft3/optional/bignum.json")
-@load_json_cases("draft3/optional/zeroTerminatedFloats.json")
-class TestDraft3(
- unittest.TestCase, TypesMixin, DecimalMixin, FormatMixin
-):
-
- validator_class = Draft3Validator
- validator_kwargs = {"format_checker" : draft3_format_checker}
-
- def test_any_type_is_valid_for_type_any(self):
- validator = self.validator_class({"type" : "any"})
- validator.validate(mock.Mock())
-
- # TODO: we're in need of more meta schema tests
- def test_invalid_properties(self):
- with self.assertRaises(SchemaError):
- validate({}, {"properties": {"test": True}},
- cls=self.validator_class)
-
- def test_minItems_invalid_string(self):
- with self.assertRaises(SchemaError):
- # needs to be an integer
- validate([1], {"minItems" : "1"}, cls=self.validator_class)
-
-
-@load_json_cases(
- "draft4/*.json", ignore_glob=os.path.join("draft4", "refRemote.json")
-)
-@load_json_cases(
- "draft4/optional/format.json", skip=missing_format(draft4_format_checker)
+from jsonschema.tests.compat import mock, unittest
+from jsonschema.validators import (
+ RefResolutionError, UnknownType, ValidationError, ErrorTree,
+ Draft3Validator, Draft4Validator, RefResolver, ValidatorMixin, validate,
)
-@load_json_cases("draft4/optional/bignum.json")
-@load_json_cases("draft4/optional/zeroTerminatedFloats.json")
-class TestDraft4(
- unittest.TestCase, TypesMixin, DecimalMixin, FormatMixin
-):
- validator_class = Draft4Validator
- validator_kwargs = {"format_checker" : draft4_format_checker}
-
- # TODO: we're in need of more meta schema tests
- def test_invalid_properties(self):
- with self.assertRaises(SchemaError):
- validate({}, {"properties": {"test": True}},
- cls=self.validator_class)
-
- def test_minItems_invalid_string(self):
- with self.assertRaises(SchemaError):
- # needs to be an integer
- validate([1], {"minItems" : "1"}, cls=self.validator_class)
-
-
-class RemoteRefResolutionMixin(object):
- def setUp(self):
- patch = mock.patch("jsonschema.validators.requests")
- requests = patch.start()
- requests.get.side_effect = self.resolve
- self.addCleanup(patch.stop)
-
- def resolve(self, reference):
- _, _, reference = reference.partition("http://localhost:1234/")
- return mock.Mock(**{"json.return_value" : REMOTES.get(reference)})
-
-
-@load_json_cases("draft3/refRemote.json")
-class Draft3RemoteResolution(RemoteRefResolutionMixin, unittest.TestCase):
- validator_class = Draft3Validator
-
-
-@load_json_cases("draft4/refRemote.json")
-class Draft4RemoteResolution(RemoteRefResolutionMixin, unittest.TestCase):
- validator_class = Draft4Validator
class TestIterErrors(unittest.TestCase):
@@ -963,60 +725,6 @@ class TestRefResolver(unittest.TestCase):
self.assertEqual(str(err.exception), "Oh no! What's this?")
-class TestFormatChecker(unittest.TestCase):
- def setUp(self):
- self.fn = mock.Mock()
-
- def test_it_can_validate_no_formats(self):
- checker = FormatChecker(formats=())
- self.assertFalse(checker.checkers)
-
- def test_it_raises_a_key_error_for_unknown_formats(self):
- with self.assertRaises(KeyError):
- FormatChecker(formats=["o noes"])
-
- def test_it_can_register_cls_checkers(self):
- with mock.patch.dict(FormatChecker.checkers, clear=True):
- FormatChecker.cls_checks("new")(self.fn)
- self.assertEqual(FormatChecker.checkers, {"new" : (self.fn, ())})
-
- def test_it_can_register_checkers(self):
- checker = FormatChecker()
- checker.checks("new")(self.fn)
- self.assertEqual(
- checker.checkers,
- dict(FormatChecker.checkers, new=(self.fn, ()))
- )
-
- def test_it_catches_registered_errors(self):
- checker = FormatChecker()
- cause = self.fn.side_effect = ValueError()
-
- checker.checks("foo", raises=ValueError)(self.fn)
-
- with self.assertRaises(FormatError) as cm:
- checker.check("bar", "foo")
-
- self.assertIs(cm.exception.cause, cause)
- self.assertIs(cm.exception.__cause__, cause)
-
- # Unregistered errors should not be caught
- self.fn.side_effect = AttributeError
- with self.assertRaises(AttributeError):
- checker.check("bar", "foo")
-
- def test_format_error_causes_become_validation_error_causes(self):
- checker = FormatChecker()
- checker.checks("foo", raises=ValueError)(self.fn)
- cause = self.fn.side_effect = ValueError()
- validator = Draft4Validator({"format" : "foo"}, format_checker=checker)
-
- with self.assertRaises(ValidationError) as cm:
- validator.validate("bar")
-
- self.assertIs(cm.exception.__cause__, cause)
-
-
def sorted_errors(errors):
def key(error):
return (
diff --git a/tox.ini b/tox.ini
index 9f2ead8..24115f5 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,7 +3,7 @@ envlist = py26, py27, pypy, py32, py33, docs, style
[testenv]
commands =
- py.test -s test_jsonschema.py
+ py.test -s jsonschema
{envpython} -m doctest README.rst
deps =
{[testenv:notpy33]deps}
@@ -22,7 +22,6 @@ commands =
deps = flake8
commands =
flake8 --max-complexity 10 jsonschema
- flake8 test_jsonschema.py
[flake8]
ignore = E203,E302,E303,E701,F811
@@ -36,7 +35,7 @@ deps =
[testenv:py33]
commands =
- py.test -s test_jsonschema.py
+ py.test -s jsonschema
{envpython} -m doctest README.rst
sphinx-build -b doctest docs {envtmpdir}/html
deps =