def test_validator_speed(benchmark): """Basic referential integrity validation speed test""" v = _Validator({ "properties": { "objs": { "type:": "array", "items": { "type": "object", "properties": { "records": { "type": "array", "items": { "type": "object", "required": ["id"] }, } }, "required": ["records"], }, }, "refs": { "type:": "array", "items": { "in_doc_ref_pattern": "/objs/*/records/*/id" }, }, } }) def do_validation(): instance = { "objs": [ { "records": [{ "id": i } for i in range(200)] }, { "records": [{ "id": i } for i in range(200, 400)] }, ], "refs": list(range(400)), } # valid v.validate(instance) # invalid try: instance["refs"].append("no ref integrity :(") v.validate(instance) except jsonschema.exceptions.ValidationError: pass except: raise benchmark.pedantic(do_validation, rounds=3)
def test_validate_in_doc_refs(): v = _Validator({ "properties": { "objs": { "type:": "array", "items": { "type": "object", "required": ["id"] }, }, "refs": { "type:": "array", "items": { "in_doc_ref_pattern": "/objs/*/id" }, }, } }) instance = { "objs": [{ "id": 1 }, { "id": "something" }], "refs": [1, "something"] } v.validate(instance) with v._validation_context(instance): assert v._in_doc_refs_cache == { "/objs/*/id": {repr(1), repr("something")} } instance = {"objs": [{"id": 1}, {"id": "something"}], "refs": [1]} v.validate(instance) with v._validation_context(instance): assert v._in_doc_refs_cache == { "/objs/*/id": {repr(1), repr("something")} } assert 2 == len([ e for e in v.safe_iter_errors({ "objs": [{ "id": 1 }, { "id": "something" }], "refs": [2, "something", "else"], }) if isinstance(e, InDocRefNotFoundError) ]) with pytest.raises(InDocRefNotFoundError): v.validate({"objs": [], "refs": ["anything"]})
def test_validator_iter_errors_in_doc_ref(): """Show that calling iter_errors directly leads to an assertion error""" validator = _Validator({ "$schema": "http://json-schema.org/draft-07/schema#", "additionalProperties": False, "type": "object", "properties": { "a": { "type": "string", "in_doc_ref_pattern": "/a" } }, }) valid_instance = {"a": "foo"} with pytest.raises( AssertionError, match="Please call _Validator.safe_iter_errors instead."): list(validator.iter_errors(valid_instance)) errors = list(validator.safe_iter_errors(valid_instance)) assert len(errors) == 0
def test_get_values_for_path_pattern(): v = _Validator({}) # Absolute path, all strings assert v._get_values_for_path_pattern( "/a/b/c", {"a": { "b": { "c": "foo", "d": "bar" } }}) == set([repr("foo")]) # Absolute path, array index assert v._get_values_for_path_pattern("/a/1/b", {"a": [{ "b": "foo" }, { "b": "bar" }]}) == set([repr("bar")]) # Absolute path, dict with a key that looks like integer assert v._get_values_for_path_pattern("/a/0/1", {"a": [{ "1": "foo" }, { "1": "bar" }]}) == set([repr("foo")]) # Absolute path, integer property assert v._get_values_for_path_pattern("/a/1", {"a": { 1: "foo", "b": "bar" }}) == set([repr("foo")]) # Absolute path, non-primitive value assert v._get_values_for_path_pattern("/a", {"a": [1, 2, 3]}) == set( [repr([1, 2, 3])]) # Path with pattern matching, array assert v._get_values_for_path_pattern( "/a/*/b", {"a": [{ "b": 1, "c": "foo" }, { "b": 2, "c": "foo" }]}) == set([repr(1), repr(2)]) # Path with pattern matching, dict assert v._get_values_for_path_pattern( "/a/*/b", {"a": { "buzz": { "b": 1, "c": "foo" }, "bazz": { "b": 2, "c": "foo" } }}) == set([repr(1), repr(2)]) # Path with pattern matching, nested assert v._get_values_for_path_pattern( "/a/*/b/*/c", { "a": [ { "b": [{ "c": 1 }, { "c": 2 }], "c": "foo" }, { "b": { "buzz": { "c": 3 }, "bazz": { "c": 4 } }, "c": "foo" }, ] }, ) == set([repr(1), repr(2), repr(3), repr(4)])