diff --git a/src/hypothesis_jsonschema/_resolve.py b/src/hypothesis_jsonschema/_resolve.py index 9a9fd7e..8362d91 100644 --- a/src/hypothesis_jsonschema/_resolve.py +++ b/src/hypothesis_jsonschema/_resolve.py @@ -25,7 +25,6 @@ HypothesisRefResolutionError, Schema, canonicalish, - merged, ) @@ -57,15 +56,9 @@ def resolve_all_refs( ) if "$ref" in schema: - s = dict(schema) - ref = s.pop("$ref") - with resolver.resolving(ref) as got: - m = merged([s, resolve_all_refs(got, resolver=resolver)]) - if m is None: # pragma: no cover - msg = f"$ref:{ref!r} had incompatible base schema {s!r}" - raise HypothesisRefResolutionError(msg) - assert "$ref" not in m - return m + # All supported drafts (04, 06, 07) ignore siblings of $ref. + with resolver.resolving(schema["$ref"]) as got: + return resolve_all_refs(got, resolver=resolver) assert "$ref" not in schema for key in SCHEMA_KEYS: diff --git a/tests/corpus-suite-schemas.json b/tests/corpus-suite-schemas.json index c911348..928b627 100644 --- a/tests/corpus-suite-schemas.json +++ b/tests/corpus-suite-schemas.json @@ -1729,6 +1729,7 @@ "propertyNames": true }, "draft7/ref overrides any sibling keywords": { + "$schema": "http://json-schema.org/draft-07/schema#", "definitions": { "reffed": { "type": "array" diff --git a/tests/test_from_schema.py b/tests/test_from_schema.py index 2e8be67..5462993 100644 --- a/tests/test_from_schema.py +++ b/tests/test_from_schema.py @@ -108,6 +108,46 @@ def test_can_generate_with_explicit_schema_version(_): pass +@pytest.mark.parametrize("draft", ["04", "06", "07"]) +@pytest.mark.parametrize("definition_key", ["definitions", "$defs"]) +@settings(deadline=None) +@given(data=st.data()) +def test_ref_siblings_do_not_resolve_against_a_subschema(data, draft, definition_key): + # GH-97: items is a sibling of $ref, and must not be resolved or applied. + ref = f"#/{definition_key}/foo" + schema = { + "$schema": f"http://json-schema.org/draft-{draft}/schema#", + definition_key: { + "foo": { + "properties": {"foo": {"type": "string"}}, + "additionalProperties": False, + }, + }, + "type": "object", + "properties": { + "bar": { + "$ref": ref, + "type": ["object", "array"], + "items": {"type": "object", "$ref": ref}, + }, + }, + } + value = data.draw(from_schema(schema)) + jsonschema.validate(value, schema) + + +@pytest.mark.parametrize("draft", ["04", "06", "07"]) +@given(data=st.data()) +def test_ref_ignores_conflicting_sibling_constraints(data, draft): + schema = { + "$schema": f"http://json-schema.org/draft-{draft}/schema#", + "definitions": {"value": {"enum": ["hello"]}}, + "$ref": "#/definitions/value", + "type": "integer", + } + assert data.draw(from_schema(schema)) == "hello" + + INVALID_SCHEMAS = { # Empty list for requires, which is invalid "Release Drafter configuration file",