From ff9f22e5cff9481aa551e75a125818b6fed901f3 Mon Sep 17 00:00:00 2001 From: Jason Desrosiers Date: Thu, 4 Mar 2021 11:47:40 -0800 Subject: [PATCH] Add tests for $dynamicRef/$dynamicAnchor What was there originally was copied and adapted from the 2019-09 test. While those tests are valid, I thought it would be easier for people to follow this complicated concept by having just two examples that are changed slightly to cover all the normal cases and edges cases related to these keywords. That ended up creating some duplication between some of the old tests with some of the new tests. I favored the new tests over the old ones when there was conflict. --- tests/draft2020-12/dynamicRef.json | 398 +++++++++++++++++++---------- 1 file changed, 263 insertions(+), 135 deletions(-) diff --git a/tests/draft2020-12/dynamicRef.json b/tests/draft2020-12/dynamicRef.json index 5f6bf8ed..2bb900a6 100644 --- a/tests/draft2020-12/dynamicRef.json +++ b/tests/draft2020-12/dynamicRef.json @@ -1,220 +1,348 @@ [ { - "description": "$dynamicRef without $dynamicAnchor works like $ref", + "description": "A $dynamicRef to a $dynamicAnchor in the same schema resource should behave like a normal $ref to an $anchor", "schema": { - "$anchor": "foo", - "properties": { - "foo": { "$dynamicRef": "#foo" } - }, - "additionalProperties": false + "type": "array", + "items": { "$dynamicRef": "#items" }, + "$defs": { + "foo": { + "$dynamicAnchor": "items", + "type": "string" + } + } }, "tests": [ { - "description": "match", - "data": {"foo": false}, - "valid": true - }, - { - "description": "recursive match", - "data": { "foo": { "foo": false } }, + "description": "An array of strings is valid", + "data": ["foo", "bar"], "valid": true }, { - "description": "mismatch", - "data": { "bar": false }, - "valid": false - }, - { - "description": "recursive mismatch", - "data": { "foo": { "bar": false } }, + "description": "An array containing non-strings is invalid", + "data": ["foo", 42], "valid": false } ] }, { - "description": "$dynamicRef without using nesting", + "description": "A $dynamicRef to an $anchor in the same schema resource should behave like a normal $ref to an $anchor", "schema": { - "$id": "http://localhost:4242/dynamicRef2/schema.json", + "type": "array", + "items": { "$dynamicRef": "#items" }, "$defs": { - "myobject": { - "$id": "myobject.json", - "$dynamicAnchor": "foo", - "anyOf": [ - { "type": "string" }, - { - "type": "object", - "additionalProperties": { "$dynamicRef": "#foo" } - } - ] + "foo": { + "$anchor": "items", + "type": "string" } - }, - "anyOf": [ - { "type": "integer" }, - { "$ref": "#/$defs/myobject" } - ] + } }, "tests": [ { - "description": "integer matches at the outer level", - "data": 1, + "description": "An array of strings is valid", + "data": ["foo", "bar"], "valid": true }, { - "description": "single level match", - "data": { "foo": "hi" }, + "description": "An array containing non-strings is invalid", + "data": ["foo", 42], + "valid": false + } + ] + }, + { + "description": "A $ref to a $dynamicAnchor in the same schema resource should behave like a normal $ref to an $anchor", + "schema": { + "type": "array", + "items": { "$ref": "#items" }, + "$defs": { + "foo": { + "$dynamicAnchor": "items", + "type": "string" + } + } + }, + "tests": [ + { + "description": "An array of strings is valid", + "data": ["foo", "bar"], "valid": true }, { - "description": "integer does not match as a property value", - "data": { "foo": 1 }, + "description": "An array containing non-strings is invalid", + "data": ["foo", 42], "valid": false - }, + } + ] + }, + { + "description": "A $dynamicRef should resolve to the first $dynamicAnchor that is encountered when the schema is evaluated", + "schema": { + "$id": "https://test.json-schema.org/typical-dynamic-resolution/root", + "$ref": "list", + "$defs": { + "foo": { + "$dynamicAnchor": "items", + "type": "string" + }, + "list": { + "$id": "list", + "type": "array", + "items": { "$dynamicRef": "#items" }, + "$defs": { + "items": { + "$comment": "This is only needed to satisfy the bookending requirement", + "$dynamicAnchor": "items" + } + } + } + } + }, + "tests": [ { - "description": "two levels, properties match with inner definition", - "data": { "foo": { "bar": "hi" } }, + "description": "An array of strings is valid", + "data": ["foo", "bar"], "valid": true }, { - "description": "two levels, no match", - "data": { "foo": { "bar": 1 } }, + "description": "An array containing non-strings is invalid", + "data": ["foo", 42], "valid": false } ] }, { - "description": "$dynamicRef with nesting", + "description": "A $dynamicRef with intermediate scopes that don't include a matching $dynamicAnchor should not affect dynamic scope resolution", "schema": { - "$id": "http://localhost:4242/dynamicRef3/schema.json", - "$dynamicAnchor": "foo", + "$id": "https://test.json-schema.org/dynamic-resolution-with-intermediate-scopes/root", + "$ref": "intermediate-scope", "$defs": { - "myobject": { - "$id": "myobject.json", - "$dynamicAnchor": "foo", - "anyOf": [ - { "type": "string" }, - { - "type": "object", - "additionalProperties": { "$dynamicRef": "#foo" } - } - ] + "foo": { + "$dynamicAnchor": "items", + "type": "string" + }, + "intermediate-scope": { + "$id": "intermediate-scope", + "$ref": "list" + }, + "list": { + "$id": "list", + "type": "array", + "items": { "$dynamicRef": "#items" }, + "$defs": { + "items": { + "$comment": "This is only needed to satisfy the bookending requirement", + "$dynamicAnchor": "items" + } + } } - }, - "anyOf": [ - { "type": "integer" }, - { "$ref": "#/$defs/myobject" } - ] + } }, "tests": [ { - "description": "integer matches at the outer level", - "data": 1, + "description": "An array of strings is valid", + "data": ["foo", "bar"], "valid": true }, { - "description": "single level match", - "data": { "foo": "hi" }, - "valid": true - }, + "description": "An array containing non-strings is invalid", + "data": ["foo", 42], + "valid": false + } + ] + }, + { + "description": "An $anchor with the same name as a $dynamicAnchor should not be used for dynamic scope resolution", + "schema": { + "$id": "https://test.json-schema.org/dynamic-resolution-ignores-anchors/root", + "$ref": "list", + "$defs": { + "foo": { + "$anchor": "items", + "type": "string" + }, + "list": { + "$id": "list", + "type": "array", + "items": { "$dynamicRef": "#items" }, + "$defs": { + "items": { + "$comment": "This is only needed to satisfy the bookending requirement", + "$dynamicAnchor": "items" + } + } + } + } + }, + "tests": [ { - "description": "integer now matches as a property value", - "data": { "foo": 1 }, + "description": "Any array is valid", + "data": ["foo", 42], "valid": true - }, + } + ] + }, + { + "description": "A $dynamicRef without a matching $dynamicAnchor in the same schema resource should behave like a normal $ref to $anchor", + "schema": { + "$id": "https://test.json-schema.org/dynamic-resolution-without-bookend/root", + "$ref": "list", + "$defs": { + "foo": { + "$dynamicAnchor": "items", + "type": "string" + }, + "list": { + "$id": "list", + "type": "array", + "items": { "$dynamicRef": "#items" }, + "$defs": { + "items": { + "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", + "$anchor": "items" + } + } + } + } + }, + "tests": [ { - "description": "two levels, properties match with inner definition", - "data": { "foo": { "bar": "hi" } }, + "description": "Any array is valid", + "data": ["foo", 42], "valid": true - }, + } + ] + }, + { + "description": "A $dynamicRef with a non-matching $dynamicAnchor in the same schema resource should behave like a normal $ref to $anchor", + "schema": { + "$id": "https://test.json-schema.org/unmatched-dynamic-anchor/root", + "$ref": "list", + "$defs": { + "foo": { + "$dynamicAnchor": "items", + "type": "string" + }, + "list": { + "$id": "list", + "type": "array", + "items": { "$dynamicRef": "#items" }, + "$defs": { + "items": { + "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", + "$anchor": "items", + "$dynamicAnchor": "foo" + } + } + } + } + }, + "tests": [ { - "description": "two levels, properties match with $dynamicRef", - "data": { "foo": { "bar": 1 } }, + "description": "Any array is valid", + "data": ["foo", 42], "valid": true } ] }, { - "description": "$dynamicRef with no $dynamicAnchor in the initial target schema resource", + "description": "A $dynamicRef that initially resolves to a schema with a matching $dynamicAnchor should resolve to the first $dynamicAnchor in the dynamic scope", "schema": { - "$id": "http://localhost:4242/dynamicRef6/base.json", - "$dynamicAnchor": "foo", - "anyOf": [ - { "type": "boolean" }, - { + "$id": "https://test.json-schema.org/relative-dynamic-reference/root", + "$dynamicAnchor": "meta", + "type": "object", + "properties": { + "foo": { "const": "pass" } + }, + "$ref": "extended", + "$defs": { + "extended": { + "$id": "extended", + "$dynamicAnchor": "meta", "type": "object", - "additionalProperties": { - "$id": "http://localhost:4242/dynamicRef6/inner.json", - "$comment": "there is no $dynamicAnchor: true here, so we do NOT recurse to the base", - "$anchor": "foo", - "anyOf": [ - { "type": "integer" }, - { "type": "object", "additionalProperties": { "$dynamicRef": "#foo" } } - ] + "properties": { + "bar": { "$ref": "bar" } + } + }, + "bar": { + "$id": "bar", + "type": "object", + "properties": { + "baz": { "$dynamicRef": "extended#meta" } } } - ] + } }, "tests": [ { - "description": "leaf node does not match; no recursion", - "data": { "foo": true }, - "valid": false - }, - { - "description": "leaf node matches: recursion uses the inner schema", - "data": { "foo": { "bar": 1 } }, + "description": "The recursive part is valid against the root", + "data": { + "foo": "pass", + "bar": { + "baz": { "foo": "pass" } + } + }, "valid": true }, { - "description": "leaf node does not match: recursion uses the inner schema", - "data": { "foo": { "bar": true } }, + "description": "The recursive part is not valid against the root", + "data": { + "foo": "pass", + "bar": { + "baz": { "foo": "fail" } + } + }, "valid": false } ] }, { - "description": "$dynamicRef with no $dynamicAnchor in the outer schema resource", + "description": "A $dynamicRef that initially resolves to a schema without a matching $dynamicAnchor should behave like a normal $ref to $anchor", "schema": { - "$id": "http://localhost:4242/dynamicRef7/base.json", - "anyOf": [ - { "type": "boolean" }, - { + "$id": "https://test.json-schema.org/relative-dynamic-reference-without-bookend/root", + "$dynamicAnchor": "meta", + "type": "object", + "properties": { + "foo": { "const": "pass" } + }, + "$ref": "extended", + "$defs": { + "extended": { + "$id": "extended", + "$anchor": "meta", "type": "object", - "additionalProperties": { - "$id": "http://localhost:4242/dynamicRef7/inner.json", - "$dynamicAnchor": "foo", - "anyOf": [ - { "type": "integer" }, - { "type": "object", "additionalProperties": { "$dynamicRef": "#foo" } } - ] + "properties": { + "bar": { "$ref": "bar" } + } + }, + "bar": { + "$id": "bar", + "type": "object", + "properties": { + "baz": { "$dynamicRef": "extended#meta" } } } - ] + } }, "tests": [ { - "description": "leaf node does not match; no recursion", - "data": { "foo": true }, - "valid": false - }, - { - "description": "leaf node matches: recursion only uses inner schema", - "data": { "foo": { "bar": 1 } }, + "description": "The recursive part doesn't need to validate against the root", + "data": { + "foo": "pass", + "bar": { + "baz": { "foo": "fail" } + } + }, "valid": true - }, - { - "description": "leaf node does not match: recursion only uses inner schema", - "data": { "foo": { "bar": true } }, - "valid": false } ] }, { "description": "multiple dynamic paths to the $dynamicRef keyword", "schema": { - "$id": "dynamicRef8_main.json", + "$id": "https://test.json-schema.org/dynamic-ref-with-multiple-paths/main", "$defs": { "inner": { - "$id": "dynamicRef8_inner.json", + "$id": "inner", "$dynamicAnchor": "foo", "title": "inner", "additionalProperties": { @@ -229,16 +357,16 @@ }, "then": { "title": "any type of node", - "$id": "dynamicRef8_anyLeafNode.json", + "$id": "anyLeafNode", "$dynamicAnchor": "foo", - "$ref": "dynamicRef8_main.json#/$defs/inner" + "$ref": "main#/$defs/inner" }, "else": { "title": "integer node", - "$id": "dynamicRef8_integerNode.json", + "$id": "integerNode", "$dynamicAnchor": "foo", "type": [ "object", "integer" ], - "$ref": "dynamicRef8_main.json#/$defs/inner" + "$ref": "main#/$defs/inner" } }, "tests": [