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)])