summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulian Berman <Julian@GrayVines.com>2021-08-25 10:33:10 +0100
committerJulian Berman <Julian@GrayVines.com>2021-08-25 10:33:10 +0100
commitebebf529e984599b411d3632385f72ec4197502a (patch)
tree5ff39fe4f3806236ecc5e71ef5406da759d3ec77
parent3992d99a74099c99cc02338ecffa5647d0a2bdc4 (diff)
downloadjsonschema-ebebf529e984599b411d3632385f72ec4197502a.tar.gz
Properly set the failing validator for min/maxContains.
Also check that only one error is raised for maxContains, which is the case right now due to short circuiting as soon as we see too many matches.
-rw-r--r--jsonschema/_validators.py4
-rw-r--r--jsonschema/tests/test_validators.py88
2 files changed, 92 insertions, 0 deletions
diff --git a/jsonschema/_validators.py b/jsonschema/_validators.py
index 0cfc8c0..c6d0e9a 100644
--- a/jsonschema/_validators.py
+++ b/jsonschema/_validators.py
@@ -118,6 +118,8 @@ def contains(validator, contains, instance, schema):
yield ValidationError(
"Too many items match the given schema "
f"(expected at most {max_contains})",
+ validator="maxContains",
+ validator_value=max_contains,
)
return
@@ -131,6 +133,8 @@ def contains(validator, contains, instance, schema):
yield ValidationError(
"Too few items match the given schema (expected at least "
f"{min_contains} but only {matches} matched)",
+ validator="minContains",
+ validator_value=min_contains,
)
diff --git a/jsonschema/tests/test_validators.py b/jsonschema/tests/test_validators.py
index 91d3819..12276e6 100644
--- a/jsonschema/tests/test_validators.py
+++ b/jsonschema/tests/test_validators.py
@@ -1221,6 +1221,94 @@ class TestValidationErrorDetails(TestCase):
),
)
+ def test_contains_too_many(self):
+ """
+ `contains` + `maxContains` produces only one error, even if there are
+ many more incorrectly matching elements.
+ """
+ schema = {"contains": {"type": "string"}, "maxContains": 2}
+ validator = validators.Draft202012Validator(schema)
+ error, = validator.iter_errors(["foo", 2, "bar", 4, "baz", "quux"])
+ self.assertEqual(
+ (
+ error.message,
+ error.validator,
+ error.validator_value,
+ error.instance,
+ error.absolute_path,
+ error.schema,
+ error.schema_path,
+ error.json_path,
+ ),
+ (
+ "Too many items match the given schema (expected at most 2)",
+ "maxContains",
+ 2,
+ ["foo", 2, "bar", 4, "baz", "quux"],
+ deque([]),
+ {"contains": {"type": "string"}, "maxContains": 2},
+ deque(["contains"]),
+ "$",
+ ),
+ )
+
+ def test_contains_too_few(self):
+ schema = {"contains": {"type": "string"}, "minContains": 2}
+ validator = validators.Draft202012Validator(schema)
+ error, = validator.iter_errors(["foo", 2, 4])
+ self.assertEqual(
+ (
+ error.message,
+ error.validator,
+ error.validator_value,
+ error.instance,
+ error.absolute_path,
+ error.schema,
+ error.schema_path,
+ error.json_path,
+ ),
+ (
+ (
+ "Too few items match the given schema "
+ "(expected at least 2 but only 1 matched)"
+ ),
+ "minContains",
+ 2,
+ ["foo", 2, 4],
+ deque([]),
+ {"contains": {"type": "string"}, "minContains": 2},
+ deque(["contains"]),
+ "$",
+ ),
+ )
+
+ def test_contains_none(self):
+ schema = {"contains": {"type": "string"}, "minContains": 2}
+ validator = validators.Draft202012Validator(schema)
+ error, = validator.iter_errors([2, 4])
+ self.assertEqual(
+ (
+ error.message,
+ error.validator,
+ error.validator_value,
+ error.instance,
+ error.absolute_path,
+ error.schema,
+ error.schema_path,
+ error.json_path,
+ ),
+ (
+ "[2, 4] does not contain items matching the given schema",
+ "contains",
+ {"type": "string"},
+ [2, 4],
+ deque([]),
+ {"contains": {"type": "string"}, "minContains": 2},
+ deque(["contains"]),
+ "$",
+ ),
+ )
+
class MetaSchemaTestsMixin(object):
# TODO: These all belong upstream