summaryrefslogtreecommitdiff
path: root/tests/draft7
diff options
context:
space:
mode:
Diffstat (limited to 'tests/draft7')
-rw-r--r--tests/draft7/additionalItems.json164
-rw-r--r--tests/draft7/additionalProperties.json147
-rw-r--r--tests/draft7/allOf.json294
-rw-r--r--tests/draft7/anyOf.json189
-rw-r--r--tests/draft7/boolean_schema.json104
-rw-r--r--tests/draft7/const.json342
-rw-r--r--tests/draft7/contains.json165
-rw-r--r--tests/draft7/default.json79
-rw-r--r--tests/draft7/definitions.json26
-rw-r--r--tests/draft7/dependencies.json248
-rw-r--r--tests/draft7/enum.json236
-rw-r--r--tests/draft7/exclusiveMaximum.json30
-rw-r--r--tests/draft7/exclusiveMinimum.json30
-rw-r--r--tests/draft7/format.json614
-rw-r--r--tests/draft7/id.json114
-rw-r--r--tests/draft7/if-then-else.json258
-rw-r--r--tests/draft7/infinite-loop-detection.json36
-rw-r--r--tests/draft7/items.json282
-rw-r--r--tests/draft7/maxItems.json44
-rw-r--r--tests/draft7/maxLength.json49
-rw-r--r--tests/draft7/maxProperties.json70
-rw-r--r--tests/draft7/maximum.json54
-rw-r--r--tests/draft7/minItems.json44
-rw-r--r--tests/draft7/minLength.json49
-rw-r--r--tests/draft7/minProperties.json54
-rw-r--r--tests/draft7/minimum.json69
-rw-r--r--tests/draft7/multipleOf.json71
-rw-r--r--tests/draft7/not.json117
-rw-r--r--tests/draft7/oneOf.json274
-rw-r--r--tests/draft7/optional/bignum.json93
-rw-r--r--tests/draft7/optional/content.json77
-rw-r--r--tests/draft7/optional/cross-draft.json25
-rw-r--r--tests/draft7/optional/ecmascript-regex.json552
-rw-r--r--tests/draft7/optional/float-overflow.json13
-rw-r--r--tests/draft7/optional/format/date-time.json133
-rw-r--r--tests/draft7/optional/format/date.json223
-rw-r--r--tests/draft7/optional/format/email.json83
-rw-r--r--tests/draft7/optional/format/hostname.json98
-rw-r--r--tests/draft7/optional/format/idn-email.json58
-rw-r--r--tests/draft7/optional/format/idn-hostname.json304
-rw-r--r--tests/draft7/optional/format/ipv4.json84
-rw-r--r--tests/draft7/optional/format/ipv6.json208
-rw-r--r--tests/draft7/optional/format/iri-reference.json73
-rw-r--r--tests/draft7/optional/format/iri.json83
-rw-r--r--tests/draft7/optional/format/json-pointer.json198
-rw-r--r--tests/draft7/optional/format/regex.json48
-rw-r--r--tests/draft7/optional/format/relative-json-pointer.json98
-rw-r--r--tests/draft7/optional/format/time.json213
-rw-r--r--tests/draft7/optional/format/unknown.json43
-rw-r--r--tests/draft7/optional/format/uri-reference.json73
-rw-r--r--tests/draft7/optional/format/uri-template.json58
-rw-r--r--tests/draft7/optional/format/uri.json138
-rw-r--r--tests/draft7/optional/non-bmp-regex.json82
-rw-r--r--tests/draft7/pattern.json59
-rw-r--r--tests/draft7/patternProperties.json171
-rw-r--r--tests/draft7/properties.json236
-rw-r--r--tests/draft7/propertyNames.json107
-rw-r--r--tests/draft7/ref.json888
-rw-r--r--tests/draft7/refRemote.json239
-rw-r--r--tests/draft7/required.json151
-rw-r--r--tests/draft7/type.json474
-rw-r--r--tests/draft7/uniqueItems.json404
-rw-r--r--tests/draft7/unknownKeyword.json56
63 files changed, 10096 insertions, 0 deletions
diff --git a/tests/draft7/additionalItems.json b/tests/draft7/additionalItems.json
new file mode 100644
index 0000000..deb44fd
--- /dev/null
+++ b/tests/draft7/additionalItems.json
@@ -0,0 +1,164 @@
+[
+ {
+ "description": "additionalItems as schema",
+ "schema": {
+ "items": [{}],
+ "additionalItems": {"type": "integer"}
+ },
+ "tests": [
+ {
+ "description": "additional items match schema",
+ "data": [ null, 2, 3, 4 ],
+ "valid": true
+ },
+ {
+ "description": "additional items do not match schema",
+ "data": [ null, 2, 3, "foo" ],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "when items is schema, additionalItems does nothing",
+ "schema": {
+ "items": {},
+ "additionalItems": false
+ },
+ "tests": [
+ {
+ "description": "all items match schema",
+ "data": [ 1, 2, 3, 4, 5 ],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "array of items with no additionalItems permitted",
+ "schema": {
+ "items": [{}, {}, {}],
+ "additionalItems": false
+ },
+ "tests": [
+ {
+ "description": "empty array",
+ "data": [ ],
+ "valid": true
+ },
+ {
+ "description": "fewer number of items present (1)",
+ "data": [ 1 ],
+ "valid": true
+ },
+ {
+ "description": "fewer number of items present (2)",
+ "data": [ 1, 2 ],
+ "valid": true
+ },
+ {
+ "description": "equal number of items present",
+ "data": [ 1, 2, 3 ],
+ "valid": true
+ },
+ {
+ "description": "additional items are not permitted",
+ "data": [ 1, 2, 3, 4 ],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "additionalItems as false without items",
+ "schema": {"additionalItems": false},
+ "tests": [
+ {
+ "description":
+ "items defaults to empty schema so everything is valid",
+ "data": [ 1, 2, 3, 4, 5 ],
+ "valid": true
+ },
+ {
+ "description": "ignores non-arrays",
+ "data": {"foo" : "bar"},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "additionalItems are allowed by default",
+ "schema": {"items": [{"type": "integer"}]},
+ "tests": [
+ {
+ "description": "only the first item is validated",
+ "data": [1, "foo", false],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "additionalItems does not look in applicators, valid case",
+ "schema": {
+ "allOf": [
+ { "items": [ { "type": "integer" } ] }
+ ],
+ "additionalItems": { "type": "boolean" }
+ },
+ "tests": [
+ {
+ "description": "items defined in allOf are not examined",
+ "data": [ 1, null ],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "additionalItems does not look in applicators, invalid case",
+ "schema": {
+ "allOf": [
+ { "items": [ { "type": "integer" }, { "type": "string" } ] }
+ ],
+ "items": [ {"type": "integer" } ],
+ "additionalItems": { "type": "boolean" }
+ },
+ "tests": [
+ {
+ "description": "items defined in allOf are not examined",
+ "data": [ 1, "hello" ],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "items validation adjusts the starting index for additionalItems",
+ "schema": {
+ "items": [ { "type": "string" } ],
+ "additionalItems": { "type": "integer" }
+ },
+ "tests": [
+ {
+ "description": "valid items",
+ "data": [ "x", 2, 3 ],
+ "valid": true
+ },
+ {
+ "description": "wrong type of second item",
+ "data": [ "x", "y" ],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "additionalItems with null instance elements",
+ "schema": {
+ "additionalItems": {
+ "type": "null"
+ }
+ },
+ "tests": [
+ {
+ "description": "allows null elements",
+ "data": [ null ],
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/additionalProperties.json b/tests/draft7/additionalProperties.json
new file mode 100644
index 0000000..0f8e162
--- /dev/null
+++ b/tests/draft7/additionalProperties.json
@@ -0,0 +1,147 @@
+[
+ {
+ "description":
+ "additionalProperties being false does not allow other properties",
+ "schema": {
+ "properties": {"foo": {}, "bar": {}},
+ "patternProperties": { "^v": {} },
+ "additionalProperties": false
+ },
+ "tests": [
+ {
+ "description": "no additional properties is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "an additional property is invalid",
+ "data": {"foo" : 1, "bar" : 2, "quux" : "boom"},
+ "valid": false
+ },
+ {
+ "description": "ignores arrays",
+ "data": [1, 2, 3],
+ "valid": true
+ },
+ {
+ "description": "ignores strings",
+ "data": "foobarbaz",
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "patternProperties are not additional properties",
+ "data": {"foo":1, "vroom": 2},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "non-ASCII pattern with additionalProperties",
+ "schema": {
+ "patternProperties": {"^á": {}},
+ "additionalProperties": false
+ },
+ "tests": [
+ {
+ "description": "matching the pattern is valid",
+ "data": {"ármányos": 2},
+ "valid": true
+ },
+ {
+ "description": "not matching the pattern is invalid",
+ "data": {"élmény": 2},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "additionalProperties with schema",
+ "schema": {
+ "properties": {"foo": {}, "bar": {}},
+ "additionalProperties": {"type": "boolean"}
+ },
+ "tests": [
+ {
+ "description": "no additional properties is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "an additional valid property is valid",
+ "data": {"foo" : 1, "bar" : 2, "quux" : true},
+ "valid": true
+ },
+ {
+ "description": "an additional invalid property is invalid",
+ "data": {"foo" : 1, "bar" : 2, "quux" : 12},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description":
+ "additionalProperties can exist by itself",
+ "schema": {
+ "additionalProperties": {"type": "boolean"}
+ },
+ "tests": [
+ {
+ "description": "an additional valid property is valid",
+ "data": {"foo" : true},
+ "valid": true
+ },
+ {
+ "description": "an additional invalid property is invalid",
+ "data": {"foo" : 1},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "additionalProperties are allowed by default",
+ "schema": {"properties": {"foo": {}, "bar": {}}},
+ "tests": [
+ {
+ "description": "additional properties are allowed",
+ "data": {"foo": 1, "bar": 2, "quux": true},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "additionalProperties does not look in applicators",
+ "schema": {
+ "allOf": [
+ {"properties": {"foo": {}}}
+ ],
+ "additionalProperties": {"type": "boolean"}
+ },
+ "tests": [
+ {
+ "description": "properties defined in allOf are not examined",
+ "data": {"foo": 1, "bar": true},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "additionalProperties with null valued instance properties",
+ "schema": {
+ "additionalProperties": {
+ "type": "null"
+ }
+ },
+ "tests": [
+ {
+ "description": "allows null values",
+ "data": {"foo": null},
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/allOf.json b/tests/draft7/allOf.json
new file mode 100644
index 0000000..ec9319e
--- /dev/null
+++ b/tests/draft7/allOf.json
@@ -0,0 +1,294 @@
+[
+ {
+ "description": "allOf",
+ "schema": {
+ "allOf": [
+ {
+ "properties": {
+ "bar": {"type": "integer"}
+ },
+ "required": ["bar"]
+ },
+ {
+ "properties": {
+ "foo": {"type": "string"}
+ },
+ "required": ["foo"]
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "allOf",
+ "data": {"foo": "baz", "bar": 2},
+ "valid": true
+ },
+ {
+ "description": "mismatch second",
+ "data": {"foo": "baz"},
+ "valid": false
+ },
+ {
+ "description": "mismatch first",
+ "data": {"bar": 2},
+ "valid": false
+ },
+ {
+ "description": "wrong type",
+ "data": {"foo": "baz", "bar": "quux"},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "allOf with base schema",
+ "schema": {
+ "properties": {"bar": {"type": "integer"}},
+ "required": ["bar"],
+ "allOf" : [
+ {
+ "properties": {
+ "foo": {"type": "string"}
+ },
+ "required": ["foo"]
+ },
+ {
+ "properties": {
+ "baz": {"type": "null"}
+ },
+ "required": ["baz"]
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "valid",
+ "data": {"foo": "quux", "bar": 2, "baz": null},
+ "valid": true
+ },
+ {
+ "description": "mismatch base schema",
+ "data": {"foo": "quux", "baz": null},
+ "valid": false
+ },
+ {
+ "description": "mismatch first allOf",
+ "data": {"bar": 2, "baz": null},
+ "valid": false
+ },
+ {
+ "description": "mismatch second allOf",
+ "data": {"foo": "quux", "bar": 2},
+ "valid": false
+ },
+ {
+ "description": "mismatch both",
+ "data": {"bar": 2},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "allOf simple types",
+ "schema": {
+ "allOf": [
+ {"maximum": 30},
+ {"minimum": 20}
+ ]
+ },
+ "tests": [
+ {
+ "description": "valid",
+ "data": 25,
+ "valid": true
+ },
+ {
+ "description": "mismatch one",
+ "data": 35,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "allOf with boolean schemas, all true",
+ "schema": {"allOf": [true, true]},
+ "tests": [
+ {
+ "description": "any value is valid",
+ "data": "foo",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "allOf with boolean schemas, some false",
+ "schema": {"allOf": [true, false]},
+ "tests": [
+ {
+ "description": "any value is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "allOf with boolean schemas, all false",
+ "schema": {"allOf": [false, false]},
+ "tests": [
+ {
+ "description": "any value is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "allOf with one empty schema",
+ "schema": {
+ "allOf": [
+ {}
+ ]
+ },
+ "tests": [
+ {
+ "description": "any data is valid",
+ "data": 1,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "allOf with two empty schemas",
+ "schema": {
+ "allOf": [
+ {},
+ {}
+ ]
+ },
+ "tests": [
+ {
+ "description": "any data is valid",
+ "data": 1,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "allOf with the first empty schema",
+ "schema": {
+ "allOf": [
+ {},
+ { "type": "number" }
+ ]
+ },
+ "tests": [
+ {
+ "description": "number is valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "string is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "allOf with the last empty schema",
+ "schema": {
+ "allOf": [
+ { "type": "number" },
+ {}
+ ]
+ },
+ "tests": [
+ {
+ "description": "number is valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "string is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "nested allOf, to check validation semantics",
+ "schema": {
+ "allOf": [
+ {
+ "allOf": [
+ {
+ "type": "null"
+ }
+ ]
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "null is valid",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "anything non-null is invalid",
+ "data": 123,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "allOf combined with anyOf, oneOf",
+ "schema": {
+ "allOf": [ { "multipleOf": 2 } ],
+ "anyOf": [ { "multipleOf": 3 } ],
+ "oneOf": [ { "multipleOf": 5 } ]
+ },
+ "tests": [
+ {
+ "description": "allOf: false, anyOf: false, oneOf: false",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "allOf: false, anyOf: false, oneOf: true",
+ "data": 5,
+ "valid": false
+ },
+ {
+ "description": "allOf: false, anyOf: true, oneOf: false",
+ "data": 3,
+ "valid": false
+ },
+ {
+ "description": "allOf: false, anyOf: true, oneOf: true",
+ "data": 15,
+ "valid": false
+ },
+ {
+ "description": "allOf: true, anyOf: false, oneOf: false",
+ "data": 2,
+ "valid": false
+ },
+ {
+ "description": "allOf: true, anyOf: false, oneOf: true",
+ "data": 10,
+ "valid": false
+ },
+ {
+ "description": "allOf: true, anyOf: true, oneOf: false",
+ "data": 6,
+ "valid": false
+ },
+ {
+ "description": "allOf: true, anyOf: true, oneOf: true",
+ "data": 30,
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/anyOf.json b/tests/draft7/anyOf.json
new file mode 100644
index 0000000..ab5eb38
--- /dev/null
+++ b/tests/draft7/anyOf.json
@@ -0,0 +1,189 @@
+[
+ {
+ "description": "anyOf",
+ "schema": {
+ "anyOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "minimum": 2
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "first anyOf valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "second anyOf valid",
+ "data": 2.5,
+ "valid": true
+ },
+ {
+ "description": "both anyOf valid",
+ "data": 3,
+ "valid": true
+ },
+ {
+ "description": "neither anyOf valid",
+ "data": 1.5,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "anyOf with base schema",
+ "schema": {
+ "type": "string",
+ "anyOf" : [
+ {
+ "maxLength": 2
+ },
+ {
+ "minLength": 4
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "mismatch base schema",
+ "data": 3,
+ "valid": false
+ },
+ {
+ "description": "one anyOf valid",
+ "data": "foobar",
+ "valid": true
+ },
+ {
+ "description": "both anyOf invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "anyOf with boolean schemas, all true",
+ "schema": {"anyOf": [true, true]},
+ "tests": [
+ {
+ "description": "any value is valid",
+ "data": "foo",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "anyOf with boolean schemas, some true",
+ "schema": {"anyOf": [true, false]},
+ "tests": [
+ {
+ "description": "any value is valid",
+ "data": "foo",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "anyOf with boolean schemas, all false",
+ "schema": {"anyOf": [false, false]},
+ "tests": [
+ {
+ "description": "any value is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "anyOf complex types",
+ "schema": {
+ "anyOf": [
+ {
+ "properties": {
+ "bar": {"type": "integer"}
+ },
+ "required": ["bar"]
+ },
+ {
+ "properties": {
+ "foo": {"type": "string"}
+ },
+ "required": ["foo"]
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "first anyOf valid (complex)",
+ "data": {"bar": 2},
+ "valid": true
+ },
+ {
+ "description": "second anyOf valid (complex)",
+ "data": {"foo": "baz"},
+ "valid": true
+ },
+ {
+ "description": "both anyOf valid (complex)",
+ "data": {"foo": "baz", "bar": 2},
+ "valid": true
+ },
+ {
+ "description": "neither anyOf valid (complex)",
+ "data": {"foo": 2, "bar": "quux"},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "anyOf with one empty schema",
+ "schema": {
+ "anyOf": [
+ { "type": "number" },
+ {}
+ ]
+ },
+ "tests": [
+ {
+ "description": "string is valid",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "number is valid",
+ "data": 123,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "nested anyOf, to check validation semantics",
+ "schema": {
+ "anyOf": [
+ {
+ "anyOf": [
+ {
+ "type": "null"
+ }
+ ]
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "null is valid",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "anything non-null is invalid",
+ "data": 123,
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/boolean_schema.json b/tests/draft7/boolean_schema.json
new file mode 100644
index 0000000..6d40f23
--- /dev/null
+++ b/tests/draft7/boolean_schema.json
@@ -0,0 +1,104 @@
+[
+ {
+ "description": "boolean schema 'true'",
+ "schema": true,
+ "tests": [
+ {
+ "description": "number is valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "string is valid",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "boolean true is valid",
+ "data": true,
+ "valid": true
+ },
+ {
+ "description": "boolean false is valid",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "null is valid",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "object is valid",
+ "data": {"foo": "bar"},
+ "valid": true
+ },
+ {
+ "description": "empty object is valid",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "array is valid",
+ "data": ["foo"],
+ "valid": true
+ },
+ {
+ "description": "empty array is valid",
+ "data": [],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "boolean schema 'false'",
+ "schema": false,
+ "tests": [
+ {
+ "description": "number is invalid",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "string is invalid",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "boolean true is invalid",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "boolean false is invalid",
+ "data": false,
+ "valid": false
+ },
+ {
+ "description": "null is invalid",
+ "data": null,
+ "valid": false
+ },
+ {
+ "description": "object is invalid",
+ "data": {"foo": "bar"},
+ "valid": false
+ },
+ {
+ "description": "empty object is invalid",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "array is invalid",
+ "data": ["foo"],
+ "valid": false
+ },
+ {
+ "description": "empty array is invalid",
+ "data": [],
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/const.json b/tests/draft7/const.json
new file mode 100644
index 0000000..1c2cafc
--- /dev/null
+++ b/tests/draft7/const.json
@@ -0,0 +1,342 @@
+[
+ {
+ "description": "const validation",
+ "schema": {"const": 2},
+ "tests": [
+ {
+ "description": "same value is valid",
+ "data": 2,
+ "valid": true
+ },
+ {
+ "description": "another value is invalid",
+ "data": 5,
+ "valid": false
+ },
+ {
+ "description": "another type is invalid",
+ "data": "a",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with object",
+ "schema": {"const": {"foo": "bar", "baz": "bax"}},
+ "tests": [
+ {
+ "description": "same object is valid",
+ "data": {"foo": "bar", "baz": "bax"},
+ "valid": true
+ },
+ {
+ "description": "same object with different property order is valid",
+ "data": {"baz": "bax", "foo": "bar"},
+ "valid": true
+ },
+ {
+ "description": "another object is invalid",
+ "data": {"foo": "bar"},
+ "valid": false
+ },
+ {
+ "description": "another type is invalid",
+ "data": [1, 2],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with array",
+ "schema": {"const": [{ "foo": "bar" }]},
+ "tests": [
+ {
+ "description": "same array is valid",
+ "data": [{"foo": "bar"}],
+ "valid": true
+ },
+ {
+ "description": "another array item is invalid",
+ "data": [2],
+ "valid": false
+ },
+ {
+ "description": "array with additional items is invalid",
+ "data": [1, 2, 3],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with null",
+ "schema": {"const": null},
+ "tests": [
+ {
+ "description": "null is valid",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "not null is invalid",
+ "data": 0,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with false does not match 0",
+ "schema": {"const": false},
+ "tests": [
+ {
+ "description": "false is valid",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "integer zero is invalid",
+ "data": 0,
+ "valid": false
+ },
+ {
+ "description": "float zero is invalid",
+ "data": 0.0,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with true does not match 1",
+ "schema": {"const": true},
+ "tests": [
+ {
+ "description": "true is valid",
+ "data": true,
+ "valid": true
+ },
+ {
+ "description": "integer one is invalid",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "float one is invalid",
+ "data": 1.0,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with [false] does not match [0]",
+ "schema": {"const": [false]},
+ "tests": [
+ {
+ "description": "[false] is valid",
+ "data": [false],
+ "valid": true
+ },
+ {
+ "description": "[0] is invalid",
+ "data": [0],
+ "valid": false
+ },
+ {
+ "description": "[0.0] is invalid",
+ "data": [0.0],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with [true] does not match [1]",
+ "schema": {"const": [true]},
+ "tests": [
+ {
+ "description": "[true] is valid",
+ "data": [true],
+ "valid": true
+ },
+ {
+ "description": "[1] is invalid",
+ "data": [1],
+ "valid": false
+ },
+ {
+ "description": "[1.0] is invalid",
+ "data": [1.0],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with {\"a\": false} does not match {\"a\": 0}",
+ "schema": {"const": {"a": false}},
+ "tests": [
+ {
+ "description": "{\"a\": false} is valid",
+ "data": {"a": false},
+ "valid": true
+ },
+ {
+ "description": "{\"a\": 0} is invalid",
+ "data": {"a": 0},
+ "valid": false
+ },
+ {
+ "description": "{\"a\": 0.0} is invalid",
+ "data": {"a": 0.0},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with {\"a\": true} does not match {\"a\": 1}",
+ "schema": {"const": {"a": true}},
+ "tests": [
+ {
+ "description": "{\"a\": true} is valid",
+ "data": {"a": true},
+ "valid": true
+ },
+ {
+ "description": "{\"a\": 1} is invalid",
+ "data": {"a": 1},
+ "valid": false
+ },
+ {
+ "description": "{\"a\": 1.0} is invalid",
+ "data": {"a": 1.0},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with 0 does not match other zero-like types",
+ "schema": {"const": 0},
+ "tests": [
+ {
+ "description": "false is invalid",
+ "data": false,
+ "valid": false
+ },
+ {
+ "description": "integer zero is valid",
+ "data": 0,
+ "valid": true
+ },
+ {
+ "description": "float zero is valid",
+ "data": 0.0,
+ "valid": true
+ },
+ {
+ "description": "empty object is invalid",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "empty array is invalid",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "empty string is invalid",
+ "data": "",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "const with 1 does not match true",
+ "schema": {"const": 1},
+ "tests": [
+ {
+ "description": "true is invalid",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "integer one is valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "float one is valid",
+ "data": 1.0,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "const with -2.0 matches integer and float types",
+ "schema": {"const": -2.0},
+ "tests": [
+ {
+ "description": "integer -2 is valid",
+ "data": -2,
+ "valid": true
+ },
+ {
+ "description": "integer 2 is invalid",
+ "data": 2,
+ "valid": false
+ },
+ {
+ "description": "float -2.0 is valid",
+ "data": -2.0,
+ "valid": true
+ },
+ {
+ "description": "float 2.0 is invalid",
+ "data": 2.0,
+ "valid": false
+ },
+ {
+ "description": "float -2.00001 is invalid",
+ "data": -2.00001,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "float and integers are equal up to 64-bit representation limits",
+ "schema": {"const": 9007199254740992},
+ "tests": [
+ {
+ "description": "integer is valid",
+ "data": 9007199254740992,
+ "valid": true
+ },
+ {
+ "description": "integer minus one is invalid",
+ "data": 9007199254740991,
+ "valid": false
+ },
+ {
+ "description": "float is valid",
+ "data": 9007199254740992.0,
+ "valid": true
+ },
+ {
+ "description": "float minus one is invalid",
+ "data": 9007199254740991.0,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "nul characters in strings",
+ "schema": { "const": "hello\u0000there" },
+ "tests": [
+ {
+ "description": "match string with nul",
+ "data": "hello\u0000there",
+ "valid": true
+ },
+ {
+ "description": "do not match string lacking nul",
+ "data": "hellothere",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/contains.json b/tests/draft7/contains.json
new file mode 100644
index 0000000..2b1a515
--- /dev/null
+++ b/tests/draft7/contains.json
@@ -0,0 +1,165 @@
+[
+ {
+ "description": "contains keyword validation",
+ "schema": {
+ "contains": {"minimum": 5}
+ },
+ "tests": [
+ {
+ "description": "array with item matching schema (5) is valid",
+ "data": [3, 4, 5],
+ "valid": true
+ },
+ {
+ "description": "array with item matching schema (6) is valid",
+ "data": [3, 4, 6],
+ "valid": true
+ },
+ {
+ "description": "array with two items matching schema (5, 6) is valid",
+ "data": [3, 4, 5, 6],
+ "valid": true
+ },
+ {
+ "description": "array without items matching schema is invalid",
+ "data": [2, 3, 4],
+ "valid": false
+ },
+ {
+ "description": "empty array is invalid",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "not array is valid",
+ "data": {},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "contains keyword with const keyword",
+ "schema": {
+ "contains": { "const": 5 }
+ },
+ "tests": [
+ {
+ "description": "array with item 5 is valid",
+ "data": [3, 4, 5],
+ "valid": true
+ },
+ {
+ "description": "array with two items 5 is valid",
+ "data": [3, 4, 5, 5],
+ "valid": true
+ },
+ {
+ "description": "array without item 5 is invalid",
+ "data": [1, 2, 3, 4],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "contains keyword with boolean schema true",
+ "schema": {"contains": true},
+ "tests": [
+ {
+ "description": "any non-empty array is valid",
+ "data": ["foo"],
+ "valid": true
+ },
+ {
+ "description": "empty array is invalid",
+ "data": [],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "contains keyword with boolean schema false",
+ "schema": {"contains": false},
+ "tests": [
+ {
+ "description": "any non-empty array is invalid",
+ "data": ["foo"],
+ "valid": false
+ },
+ {
+ "description": "empty array is invalid",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "non-arrays are valid",
+ "data": "contains does not apply to strings",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "items + contains",
+ "schema": {
+ "items": { "multipleOf": 2 },
+ "contains": { "multipleOf": 3 }
+ },
+ "tests": [
+ {
+ "description": "matches items, does not match contains",
+ "data": [ 2, 4, 8 ],
+ "valid": false
+ },
+ {
+ "description": "does not match items, matches contains",
+ "data": [ 3, 6, 9 ],
+ "valid": false
+ },
+ {
+ "description": "matches both items and contains",
+ "data": [ 6, 12 ],
+ "valid": true
+ },
+ {
+ "description": "matches neither items nor contains",
+ "data": [ 1, 5 ],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "contains with false if subschema",
+ "schema": {
+ "contains": {
+ "if": false,
+ "else": true
+ }
+ },
+ "tests": [
+ {
+ "description": "any non-empty array is valid",
+ "data": ["foo"],
+ "valid": true
+ },
+ {
+ "description": "empty array is invalid",
+ "data": [],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "contains with null instance elements",
+ "schema": {
+ "contains": {
+ "type": "null"
+ }
+ },
+ "tests": [
+ {
+ "description": "allows null items",
+ "data": [ null ],
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/default.json b/tests/draft7/default.json
new file mode 100644
index 0000000..289a9b6
--- /dev/null
+++ b/tests/draft7/default.json
@@ -0,0 +1,79 @@
+[
+ {
+ "description": "invalid type for default",
+ "schema": {
+ "properties": {
+ "foo": {
+ "type": "integer",
+ "default": []
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "valid when property is specified",
+ "data": {"foo": 13},
+ "valid": true
+ },
+ {
+ "description": "still valid when the invalid default is used",
+ "data": {},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "invalid string value for default",
+ "schema": {
+ "properties": {
+ "bar": {
+ "type": "string",
+ "minLength": 4,
+ "default": "bad"
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "valid when property is specified",
+ "data": {"bar": "good"},
+ "valid": true
+ },
+ {
+ "description": "still valid when the invalid default is used",
+ "data": {},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "the default keyword does not do anything if the property is missing",
+ "schema": {
+ "type": "object",
+ "properties": {
+ "alpha": {
+ "type": "number",
+ "maximum": 3,
+ "default": 5
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "an explicit property value is checked against maximum (passing)",
+ "data": { "alpha": 1 },
+ "valid": true
+ },
+ {
+ "description": "an explicit property value is checked against maximum (failing)",
+ "data": { "alpha": 5 },
+ "valid": false
+ },
+ {
+ "description": "missing properties are not filled in with the default",
+ "data": {},
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/definitions.json b/tests/draft7/definitions.json
new file mode 100644
index 0000000..afe396e
--- /dev/null
+++ b/tests/draft7/definitions.json
@@ -0,0 +1,26 @@
+[
+ {
+ "description": "validate definition against metaschema",
+ "schema": {"$ref": "http://json-schema.org/draft-07/schema#"},
+ "tests": [
+ {
+ "description": "valid definition schema",
+ "data": {
+ "definitions": {
+ "foo": {"type": "integer"}
+ }
+ },
+ "valid": true
+ },
+ {
+ "description": "invalid definition schema",
+ "data": {
+ "definitions": {
+ "foo": {"type": 1}
+ }
+ },
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/dependencies.json b/tests/draft7/dependencies.json
new file mode 100644
index 0000000..a5e5428
--- /dev/null
+++ b/tests/draft7/dependencies.json
@@ -0,0 +1,248 @@
+[
+ {
+ "description": "dependencies",
+ "schema": {
+ "dependencies": {"bar": ["foo"]}
+ },
+ "tests": [
+ {
+ "description": "neither",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "nondependant",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "with dependency",
+ "data": {"foo": 1, "bar": 2},
+ "valid": true
+ },
+ {
+ "description": "missing dependency",
+ "data": {"bar": 2},
+ "valid": false
+ },
+ {
+ "description": "ignores arrays",
+ "data": ["bar"],
+ "valid": true
+ },
+ {
+ "description": "ignores strings",
+ "data": "foobar",
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "dependencies with empty array",
+ "schema": {
+ "dependencies": {"bar": []}
+ },
+ "tests": [
+ {
+ "description": "empty object",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "object with one property",
+ "data": {"bar": 2},
+ "valid": true
+ },
+ {
+ "description": "non-object is valid",
+ "data": 1,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "multiple dependencies",
+ "schema": {
+ "dependencies": {"quux": ["foo", "bar"]}
+ },
+ "tests": [
+ {
+ "description": "neither",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "nondependants",
+ "data": {"foo": 1, "bar": 2},
+ "valid": true
+ },
+ {
+ "description": "with dependencies",
+ "data": {"foo": 1, "bar": 2, "quux": 3},
+ "valid": true
+ },
+ {
+ "description": "missing dependency",
+ "data": {"foo": 1, "quux": 2},
+ "valid": false
+ },
+ {
+ "description": "missing other dependency",
+ "data": {"bar": 1, "quux": 2},
+ "valid": false
+ },
+ {
+ "description": "missing both dependencies",
+ "data": {"quux": 1},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "multiple dependencies subschema",
+ "schema": {
+ "dependencies": {
+ "bar": {
+ "properties": {
+ "foo": {"type": "integer"},
+ "bar": {"type": "integer"}
+ }
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "valid",
+ "data": {"foo": 1, "bar": 2},
+ "valid": true
+ },
+ {
+ "description": "no dependency",
+ "data": {"foo": "quux"},
+ "valid": true
+ },
+ {
+ "description": "wrong type",
+ "data": {"foo": "quux", "bar": 2},
+ "valid": false
+ },
+ {
+ "description": "wrong type other",
+ "data": {"foo": 2, "bar": "quux"},
+ "valid": false
+ },
+ {
+ "description": "wrong type both",
+ "data": {"foo": "quux", "bar": "quux"},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "dependencies with boolean subschemas",
+ "schema": {
+ "dependencies": {
+ "foo": true,
+ "bar": false
+ }
+ },
+ "tests": [
+ {
+ "description": "object with property having schema true is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "object with property having schema false is invalid",
+ "data": {"bar": 2},
+ "valid": false
+ },
+ {
+ "description": "object with both properties is invalid",
+ "data": {"foo": 1, "bar": 2},
+ "valid": false
+ },
+ {
+ "description": "empty object is valid",
+ "data": {},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "dependencies with escaped characters",
+ "schema": {
+ "dependencies": {
+ "foo\nbar": ["foo\rbar"],
+ "foo\tbar": {
+ "minProperties": 4
+ },
+ "foo'bar": {"required": ["foo\"bar"]},
+ "foo\"bar": ["foo'bar"]
+ }
+ },
+ "tests": [
+ {
+ "description": "valid object 1",
+ "data": {
+ "foo\nbar": 1,
+ "foo\rbar": 2
+ },
+ "valid": true
+ },
+ {
+ "description": "valid object 2",
+ "data": {
+ "foo\tbar": 1,
+ "a": 2,
+ "b": 3,
+ "c": 4
+ },
+ "valid": true
+ },
+ {
+ "description": "valid object 3",
+ "data": {
+ "foo'bar": 1,
+ "foo\"bar": 2
+ },
+ "valid": true
+ },
+ {
+ "description": "invalid object 1",
+ "data": {
+ "foo\nbar": 1,
+ "foo": 2
+ },
+ "valid": false
+ },
+ {
+ "description": "invalid object 2",
+ "data": {
+ "foo\tbar": 1,
+ "a": 2
+ },
+ "valid": false
+ },
+ {
+ "description": "invalid object 3",
+ "data": {
+ "foo'bar": 1
+ },
+ "valid": false
+ },
+ {
+ "description": "invalid object 4",
+ "data": {
+ "foo\"bar": 2
+ },
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/enum.json b/tests/draft7/enum.json
new file mode 100644
index 0000000..f085097
--- /dev/null
+++ b/tests/draft7/enum.json
@@ -0,0 +1,236 @@
+[
+ {
+ "description": "simple enum validation",
+ "schema": {"enum": [1, 2, 3]},
+ "tests": [
+ {
+ "description": "one of the enum is valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "something else is invalid",
+ "data": 4,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "heterogeneous enum validation",
+ "schema": {"enum": [6, "foo", [], true, {"foo": 12}]},
+ "tests": [
+ {
+ "description": "one of the enum is valid",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "something else is invalid",
+ "data": null,
+ "valid": false
+ },
+ {
+ "description": "objects are deep compared",
+ "data": {"foo": false},
+ "valid": false
+ },
+ {
+ "description": "valid object matches",
+ "data": {"foo": 12},
+ "valid": true
+ },
+ {
+ "description": "extra properties in object is invalid",
+ "data": {"foo": 12, "boo": 42},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "heterogeneous enum-with-null validation",
+ "schema": { "enum": [6, null] },
+ "tests": [
+ {
+ "description": "null is valid",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "number is valid",
+ "data": 6,
+ "valid": true
+ },
+ {
+ "description": "something else is invalid",
+ "data": "test",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "enums in properties",
+ "schema": {
+ "type":"object",
+ "properties": {
+ "foo": {"enum":["foo"]},
+ "bar": {"enum":["bar"]}
+ },
+ "required": ["bar"]
+ },
+ "tests": [
+ {
+ "description": "both properties are valid",
+ "data": {"foo":"foo", "bar":"bar"},
+ "valid": true
+ },
+ {
+ "description": "wrong foo value",
+ "data": {"foo":"foot", "bar":"bar"},
+ "valid": false
+ },
+ {
+ "description": "wrong bar value",
+ "data": {"foo":"foo", "bar":"bart"},
+ "valid": false
+ },
+ {
+ "description": "missing optional property is valid",
+ "data": {"bar":"bar"},
+ "valid": true
+ },
+ {
+ "description": "missing required property is invalid",
+ "data": {"foo":"foo"},
+ "valid": false
+ },
+ {
+ "description": "missing all properties is invalid",
+ "data": {},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "enum with escaped characters",
+ "schema": {
+ "enum": ["foo\nbar", "foo\rbar"]
+ },
+ "tests": [
+ {
+ "description": "member 1 is valid",
+ "data": "foo\nbar",
+ "valid": true
+ },
+ {
+ "description": "member 2 is valid",
+ "data": "foo\rbar",
+ "valid": true
+ },
+ {
+ "description": "another string is invalid",
+ "data": "abc",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "enum with false does not match 0",
+ "schema": {"enum": [false]},
+ "tests": [
+ {
+ "description": "false is valid",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "integer zero is invalid",
+ "data": 0,
+ "valid": false
+ },
+ {
+ "description": "float zero is invalid",
+ "data": 0.0,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "enum with true does not match 1",
+ "schema": {"enum": [true]},
+ "tests": [
+ {
+ "description": "true is valid",
+ "data": true,
+ "valid": true
+ },
+ {
+ "description": "integer one is invalid",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "float one is invalid",
+ "data": 1.0,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "enum with 0 does not match false",
+ "schema": {"enum": [0]},
+ "tests": [
+ {
+ "description": "false is invalid",
+ "data": false,
+ "valid": false
+ },
+ {
+ "description": "integer zero is valid",
+ "data": 0,
+ "valid": true
+ },
+ {
+ "description": "float zero is valid",
+ "data": 0.0,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "enum with 1 does not match true",
+ "schema": {"enum": [1]},
+ "tests": [
+ {
+ "description": "true is invalid",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "integer one is valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "float one is valid",
+ "data": 1.0,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "nul characters in strings",
+ "schema": { "enum": [ "hello\u0000there" ] },
+ "tests": [
+ {
+ "description": "match string with nul",
+ "data": "hello\u0000there",
+ "valid": true
+ },
+ {
+ "description": "do not match string lacking nul",
+ "data": "hellothere",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/exclusiveMaximum.json b/tests/draft7/exclusiveMaximum.json
new file mode 100644
index 0000000..dc3cd70
--- /dev/null
+++ b/tests/draft7/exclusiveMaximum.json
@@ -0,0 +1,30 @@
+[
+ {
+ "description": "exclusiveMaximum validation",
+ "schema": {
+ "exclusiveMaximum": 3.0
+ },
+ "tests": [
+ {
+ "description": "below the exclusiveMaximum is valid",
+ "data": 2.2,
+ "valid": true
+ },
+ {
+ "description": "boundary point is invalid",
+ "data": 3.0,
+ "valid": false
+ },
+ {
+ "description": "above the exclusiveMaximum is invalid",
+ "data": 3.5,
+ "valid": false
+ },
+ {
+ "description": "ignores non-numbers",
+ "data": "x",
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/exclusiveMinimum.json b/tests/draft7/exclusiveMinimum.json
new file mode 100644
index 0000000..b38d7ec
--- /dev/null
+++ b/tests/draft7/exclusiveMinimum.json
@@ -0,0 +1,30 @@
+[
+ {
+ "description": "exclusiveMinimum validation",
+ "schema": {
+ "exclusiveMinimum": 1.1
+ },
+ "tests": [
+ {
+ "description": "above the exclusiveMinimum is valid",
+ "data": 1.2,
+ "valid": true
+ },
+ {
+ "description": "boundary point is invalid",
+ "data": 1.1,
+ "valid": false
+ },
+ {
+ "description": "below the exclusiveMinimum is invalid",
+ "data": 0.6,
+ "valid": false
+ },
+ {
+ "description": "ignores non-numbers",
+ "data": "x",
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/format.json b/tests/draft7/format.json
new file mode 100644
index 0000000..e2447d6
--- /dev/null
+++ b/tests/draft7/format.json
@@ -0,0 +1,614 @@
+[
+ {
+ "description": "email format",
+ "schema": { "format": "email" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "idn-email format",
+ "schema": { "format": "idn-email" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "regex format",
+ "schema": { "format": "regex" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ipv4 format",
+ "schema": { "format": "ipv4" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ipv6 format",
+ "schema": { "format": "ipv6" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "idn-hostname format",
+ "schema": { "format": "idn-hostname" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "hostname format",
+ "schema": { "format": "hostname" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "date format",
+ "schema": { "format": "date" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "date-time format",
+ "schema": { "format": "date-time" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "time format",
+ "schema": { "format": "time" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "json-pointer format",
+ "schema": { "format": "json-pointer" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "relative-json-pointer format",
+ "schema": { "format": "relative-json-pointer" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "iri format",
+ "schema": { "format": "iri" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "iri-reference format",
+ "schema": { "format": "iri-reference" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "uri format",
+ "schema": { "format": "uri" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "uri-reference format",
+ "schema": { "format": "uri-reference" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "uri-template format",
+ "schema": { "format": "uri-template" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/id.json b/tests/draft7/id.json
new file mode 100644
index 0000000..6be81b8
--- /dev/null
+++ b/tests/draft7/id.json
@@ -0,0 +1,114 @@
+[
+ {
+ "description": "id inside an enum is not a real identifier",
+ "comment": "the implementation must not be confused by an id buried in the enum",
+ "schema": {
+ "definitions": {
+ "id_in_enum": {
+ "enum": [
+ {
+ "$id": "https://localhost:1234/id/my_identifier.json",
+ "type": "null"
+ }
+ ]
+ },
+ "real_id_in_schema": {
+ "$id": "https://localhost:1234/id/my_identifier.json",
+ "type": "string"
+ },
+ "zzz_id_in_const": {
+ "const": {
+ "$id": "https://localhost:1234/id/my_identifier.json",
+ "type": "null"
+ }
+ }
+ },
+ "anyOf": [
+ { "$ref": "#/definitions/id_in_enum" },
+ { "$ref": "https://localhost:1234/id/my_identifier.json" }
+ ]
+ },
+ "tests": [
+ {
+ "description": "exact match to enum, and type matches",
+ "data": {
+ "$id": "https://localhost:1234/id/my_identifier.json",
+ "type": "null"
+ },
+ "valid": true
+ },
+ {
+ "description": "match $ref to id",
+ "data": "a string to match #/definitions/id_in_enum",
+ "valid": true
+ },
+ {
+ "description": "no match on enum or $ref to id",
+ "data": 1,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "non-schema object containing a plain-name $id property",
+ "schema": {
+ "definitions": {
+ "const_not_anchor": {
+ "const": {
+ "$id": "#not_a_real_anchor"
+ }
+ }
+ },
+ "if": {
+ "const": "skip not_a_real_anchor"
+ },
+ "then": true,
+ "else" : {
+ "$ref": "#/definitions/const_not_anchor"
+ }
+ },
+ "tests": [
+ {
+ "description": "skip traversing definition for a valid result",
+ "data": "skip not_a_real_anchor",
+ "valid": true
+ },
+ {
+ "description": "const at const_not_anchor does not match",
+ "data": 1,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "non-schema object containing an $id property",
+ "schema": {
+ "definitions": {
+ "const_not_id": {
+ "const": {
+ "$id": "not_a_real_id"
+ }
+ }
+ },
+ "if": {
+ "const": "skip not_a_real_id"
+ },
+ "then": true,
+ "else" : {
+ "$ref": "#/definitions/const_not_id"
+ }
+ },
+ "tests": [
+ {
+ "description": "skip traversing definition for a valid result",
+ "data": "skip not_a_real_id",
+ "valid": true
+ },
+ {
+ "description": "const at const_not_id does not match",
+ "data": 1,
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/if-then-else.json b/tests/draft7/if-then-else.json
new file mode 100644
index 0000000..284e919
--- /dev/null
+++ b/tests/draft7/if-then-else.json
@@ -0,0 +1,258 @@
+[
+ {
+ "description": "ignore if without then or else",
+ "schema": {
+ "if": {
+ "const": 0
+ }
+ },
+ "tests": [
+ {
+ "description": "valid when valid against lone if",
+ "data": 0,
+ "valid": true
+ },
+ {
+ "description": "valid when invalid against lone if",
+ "data": "hello",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ignore then without if",
+ "schema": {
+ "then": {
+ "const": 0
+ }
+ },
+ "tests": [
+ {
+ "description": "valid when valid against lone then",
+ "data": 0,
+ "valid": true
+ },
+ {
+ "description": "valid when invalid against lone then",
+ "data": "hello",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ignore else without if",
+ "schema": {
+ "else": {
+ "const": 0
+ }
+ },
+ "tests": [
+ {
+ "description": "valid when valid against lone else",
+ "data": 0,
+ "valid": true
+ },
+ {
+ "description": "valid when invalid against lone else",
+ "data": "hello",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "if and then without else",
+ "schema": {
+ "if": {
+ "exclusiveMaximum": 0
+ },
+ "then": {
+ "minimum": -10
+ }
+ },
+ "tests": [
+ {
+ "description": "valid through then",
+ "data": -1,
+ "valid": true
+ },
+ {
+ "description": "invalid through then",
+ "data": -100,
+ "valid": false
+ },
+ {
+ "description": "valid when if test fails",
+ "data": 3,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "if and else without then",
+ "schema": {
+ "if": {
+ "exclusiveMaximum": 0
+ },
+ "else": {
+ "multipleOf": 2
+ }
+ },
+ "tests": [
+ {
+ "description": "valid when if test passes",
+ "data": -1,
+ "valid": true
+ },
+ {
+ "description": "valid through else",
+ "data": 4,
+ "valid": true
+ },
+ {
+ "description": "invalid through else",
+ "data": 3,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "validate against correct branch, then vs else",
+ "schema": {
+ "if": {
+ "exclusiveMaximum": 0
+ },
+ "then": {
+ "minimum": -10
+ },
+ "else": {
+ "multipleOf": 2
+ }
+ },
+ "tests": [
+ {
+ "description": "valid through then",
+ "data": -1,
+ "valid": true
+ },
+ {
+ "description": "invalid through then",
+ "data": -100,
+ "valid": false
+ },
+ {
+ "description": "valid through else",
+ "data": 4,
+ "valid": true
+ },
+ {
+ "description": "invalid through else",
+ "data": 3,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "non-interference across combined schemas",
+ "schema": {
+ "allOf": [
+ {
+ "if": {
+ "exclusiveMaximum": 0
+ }
+ },
+ {
+ "then": {
+ "minimum": -10
+ }
+ },
+ {
+ "else": {
+ "multipleOf": 2
+ }
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "valid, but would have been invalid through then",
+ "data": -100,
+ "valid": true
+ },
+ {
+ "description": "valid, but would have been invalid through else",
+ "data": 3,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "if with boolean schema true",
+ "schema": {
+ "if": true,
+ "then": { "const": "then" },
+ "else": { "const": "else" }
+ },
+ "tests": [
+ {
+ "description": "boolean schema true in if always chooses the then path (valid)",
+ "data": "then",
+ "valid": true
+ },
+ {
+ "description": "boolean schema true in if always chooses the then path (invalid)",
+ "data": "else",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "if with boolean schema false",
+ "schema": {
+ "if": false,
+ "then": { "const": "then" },
+ "else": { "const": "else" }
+ },
+ "tests": [
+ {
+ "description": "boolean schema false in if always chooses the else path (invalid)",
+ "data": "then",
+ "valid": false
+ },
+ {
+ "description": "boolean schema false in if always chooses the else path (valid)",
+ "data": "else",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "if appears at the end when serialized (keyword processing sequence)",
+ "schema": {
+ "then": { "const": "yes" },
+ "else": { "const": "other" },
+ "if": { "maxLength": 4 }
+ },
+ "tests": [
+ {
+ "description": "yes redirects to then and passes",
+ "data": "yes",
+ "valid": true
+ },
+ {
+ "description": "other redirects to else and passes",
+ "data": "other",
+ "valid": true
+ },
+ {
+ "description": "no redirects to then and fails",
+ "data": "no",
+ "valid": false
+ },
+ {
+ "description": "invalid redirects to else and fails",
+ "data": "invalid",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/infinite-loop-detection.json b/tests/draft7/infinite-loop-detection.json
new file mode 100644
index 0000000..f98c74f
--- /dev/null
+++ b/tests/draft7/infinite-loop-detection.json
@@ -0,0 +1,36 @@
+[
+ {
+ "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop",
+ "schema": {
+ "definitions": {
+ "int": { "type": "integer" }
+ },
+ "allOf": [
+ {
+ "properties": {
+ "foo": {
+ "$ref": "#/definitions/int"
+ }
+ }
+ },
+ {
+ "additionalProperties": {
+ "$ref": "#/definitions/int"
+ }
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "passing case",
+ "data": { "foo": 1 },
+ "valid": true
+ },
+ {
+ "description": "failing case",
+ "data": { "foo": "a string" },
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/items.json b/tests/draft7/items.json
new file mode 100644
index 0000000..7ed6781
--- /dev/null
+++ b/tests/draft7/items.json
@@ -0,0 +1,282 @@
+[
+ {
+ "description": "a schema given for items",
+ "schema": {
+ "items": {"type": "integer"}
+ },
+ "tests": [
+ {
+ "description": "valid items",
+ "data": [ 1, 2, 3 ],
+ "valid": true
+ },
+ {
+ "description": "wrong type of items",
+ "data": [1, "x"],
+ "valid": false
+ },
+ {
+ "description": "ignores non-arrays",
+ "data": {"foo" : "bar"},
+ "valid": true
+ },
+ {
+ "description": "JavaScript pseudo-array is valid",
+ "data": {
+ "0": "invalid",
+ "length": 1
+ },
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "an array of schemas for items",
+ "schema": {
+ "items": [
+ {"type": "integer"},
+ {"type": "string"}
+ ]
+ },
+ "tests": [
+ {
+ "description": "correct types",
+ "data": [ 1, "foo" ],
+ "valid": true
+ },
+ {
+ "description": "wrong types",
+ "data": [ "foo", 1 ],
+ "valid": false
+ },
+ {
+ "description": "incomplete array of items",
+ "data": [ 1 ],
+ "valid": true
+ },
+ {
+ "description": "array with additional items",
+ "data": [ 1, "foo", true ],
+ "valid": true
+ },
+ {
+ "description": "empty array",
+ "data": [ ],
+ "valid": true
+ },
+ {
+ "description": "JavaScript pseudo-array is valid",
+ "data": {
+ "0": "invalid",
+ "1": "valid",
+ "length": 2
+ },
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "items with boolean schema (true)",
+ "schema": {"items": true},
+ "tests": [
+ {
+ "description": "any array is valid",
+ "data": [ 1, "foo", true ],
+ "valid": true
+ },
+ {
+ "description": "empty array is valid",
+ "data": [],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "items with boolean schema (false)",
+ "schema": {"items": false},
+ "tests": [
+ {
+ "description": "any non-empty array is invalid",
+ "data": [ 1, "foo", true ],
+ "valid": false
+ },
+ {
+ "description": "empty array is valid",
+ "data": [],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "items with boolean schemas",
+ "schema": {
+ "items": [true, false]
+ },
+ "tests": [
+ {
+ "description": "array with one item is valid",
+ "data": [ 1 ],
+ "valid": true
+ },
+ {
+ "description": "array with two items is invalid",
+ "data": [ 1, "foo" ],
+ "valid": false
+ },
+ {
+ "description": "empty array is valid",
+ "data": [],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "items and subitems",
+ "schema": {
+ "definitions": {
+ "item": {
+ "type": "array",
+ "additionalItems": false,
+ "items": [
+ { "$ref": "#/definitions/sub-item" },
+ { "$ref": "#/definitions/sub-item" }
+ ]
+ },
+ "sub-item": {
+ "type": "object",
+ "required": ["foo"]
+ }
+ },
+ "type": "array",
+ "additionalItems": false,
+ "items": [
+ { "$ref": "#/definitions/item" },
+ { "$ref": "#/definitions/item" },
+ { "$ref": "#/definitions/item" }
+ ]
+ },
+ "tests": [
+ {
+ "description": "valid items",
+ "data": [
+ [ {"foo": null}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ]
+ ],
+ "valid": true
+ },
+ {
+ "description": "too many items",
+ "data": [
+ [ {"foo": null}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ]
+ ],
+ "valid": false
+ },
+ {
+ "description": "too many sub-items",
+ "data": [
+ [ {"foo": null}, {"foo": null}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ]
+ ],
+ "valid": false
+ },
+ {
+ "description": "wrong item",
+ "data": [
+ {"foo": null},
+ [ {"foo": null}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ]
+ ],
+ "valid": false
+ },
+ {
+ "description": "wrong sub-item",
+ "data": [
+ [ {}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ],
+ [ {"foo": null}, {"foo": null} ]
+ ],
+ "valid": false
+ },
+ {
+ "description": "fewer items is valid",
+ "data": [
+ [ {"foo": null} ],
+ [ {"foo": null} ]
+ ],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "nested items",
+ "schema": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "array",
+ "items": {
+ "type": "number"
+ }
+ }
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "valid nested array",
+ "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]],
+ "valid": true
+ },
+ {
+ "description": "nested array with invalid type",
+ "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]],
+ "valid": false
+ },
+ {
+ "description": "not deep enough",
+ "data": [[[1], [2],[3]], [[4], [5], [6]]],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "single-form items with null instance elements",
+ "schema": {
+ "items": {
+ "type": "null"
+ }
+ },
+ "tests": [
+ {
+ "description": "allows null elements",
+ "data": [ null ],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "array-form items with null instance elements",
+ "schema": {
+ "items": [
+ {
+ "type": "null"
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "allows null elements",
+ "data": [ null ],
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/maxItems.json b/tests/draft7/maxItems.json
new file mode 100644
index 0000000..f0c36ab
--- /dev/null
+++ b/tests/draft7/maxItems.json
@@ -0,0 +1,44 @@
+[
+ {
+ "description": "maxItems validation",
+ "schema": {"maxItems": 2},
+ "tests": [
+ {
+ "description": "shorter is valid",
+ "data": [1],
+ "valid": true
+ },
+ {
+ "description": "exact length is valid",
+ "data": [1, 2],
+ "valid": true
+ },
+ {
+ "description": "too long is invalid",
+ "data": [1, 2, 3],
+ "valid": false
+ },
+ {
+ "description": "ignores non-arrays",
+ "data": "foobar",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "maxItems validation with a decimal",
+ "schema": {"maxItems": 2.0},
+ "tests": [
+ {
+ "description": "shorter is valid",
+ "data": [1],
+ "valid": true
+ },
+ {
+ "description": "too long is invalid",
+ "data": [1, 2, 3],
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/maxLength.json b/tests/draft7/maxLength.json
new file mode 100644
index 0000000..748b4da
--- /dev/null
+++ b/tests/draft7/maxLength.json
@@ -0,0 +1,49 @@
+[
+ {
+ "description": "maxLength validation",
+ "schema": {"maxLength": 2},
+ "tests": [
+ {
+ "description": "shorter is valid",
+ "data": "f",
+ "valid": true
+ },
+ {
+ "description": "exact length is valid",
+ "data": "fo",
+ "valid": true
+ },
+ {
+ "description": "too long is invalid",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "ignores non-strings",
+ "data": 100,
+ "valid": true
+ },
+ {
+ "description": "two supplementary Unicode code points is long enough",
+ "data": "\uD83D\uDCA9\uD83D\uDCA9",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "maxLength validation with a decimal",
+ "schema": {"maxLength": 2.0},
+ "tests": [
+ {
+ "description": "shorter is valid",
+ "data": "f",
+ "valid": true
+ },
+ {
+ "description": "too long is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/maxProperties.json b/tests/draft7/maxProperties.json
new file mode 100644
index 0000000..acec142
--- /dev/null
+++ b/tests/draft7/maxProperties.json
@@ -0,0 +1,70 @@
+[
+ {
+ "description": "maxProperties validation",
+ "schema": {"maxProperties": 2},
+ "tests": [
+ {
+ "description": "shorter is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "exact length is valid",
+ "data": {"foo": 1, "bar": 2},
+ "valid": true
+ },
+ {
+ "description": "too long is invalid",
+ "data": {"foo": 1, "bar": 2, "baz": 3},
+ "valid": false
+ },
+ {
+ "description": "ignores arrays",
+ "data": [1, 2, 3],
+ "valid": true
+ },
+ {
+ "description": "ignores strings",
+ "data": "foobar",
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "maxProperties validation with a decimal",
+ "schema": {"maxProperties": 2.0},
+ "tests": [
+ {
+ "description": "shorter is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "too long is invalid",
+ "data": {"foo": 1, "bar": 2, "baz": 3},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "maxProperties = 0 means the object is empty",
+ "schema": { "maxProperties": 0 },
+ "tests": [
+ {
+ "description": "no properties is valid",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "one property is invalid",
+ "data": { "foo": 1 },
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/maximum.json b/tests/draft7/maximum.json
new file mode 100644
index 0000000..6844a39
--- /dev/null
+++ b/tests/draft7/maximum.json
@@ -0,0 +1,54 @@
+[
+ {
+ "description": "maximum validation",
+ "schema": {"maximum": 3.0},
+ "tests": [
+ {
+ "description": "below the maximum is valid",
+ "data": 2.6,
+ "valid": true
+ },
+ {
+ "description": "boundary point is valid",
+ "data": 3.0,
+ "valid": true
+ },
+ {
+ "description": "above the maximum is invalid",
+ "data": 3.5,
+ "valid": false
+ },
+ {
+ "description": "ignores non-numbers",
+ "data": "x",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "maximum validation with unsigned integer",
+ "schema": {"maximum": 300},
+ "tests": [
+ {
+ "description": "below the maximum is invalid",
+ "data": 299.97,
+ "valid": true
+ },
+ {
+ "description": "boundary point integer is valid",
+ "data": 300,
+ "valid": true
+ },
+ {
+ "description": "boundary point float is valid",
+ "data": 300.00,
+ "valid": true
+ },
+ {
+ "description": "above the maximum is invalid",
+ "data": 300.5,
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/minItems.json b/tests/draft7/minItems.json
new file mode 100644
index 0000000..d3b1872
--- /dev/null
+++ b/tests/draft7/minItems.json
@@ -0,0 +1,44 @@
+[
+ {
+ "description": "minItems validation",
+ "schema": {"minItems": 1},
+ "tests": [
+ {
+ "description": "longer is valid",
+ "data": [1, 2],
+ "valid": true
+ },
+ {
+ "description": "exact length is valid",
+ "data": [1],
+ "valid": true
+ },
+ {
+ "description": "too short is invalid",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "ignores non-arrays",
+ "data": "",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "minItems validation with a decimal",
+ "schema": {"minItems": 1.0},
+ "tests": [
+ {
+ "description": "longer is valid",
+ "data": [1, 2],
+ "valid": true
+ },
+ {
+ "description": "too short is invalid",
+ "data": [],
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/minLength.json b/tests/draft7/minLength.json
new file mode 100644
index 0000000..64db948
--- /dev/null
+++ b/tests/draft7/minLength.json
@@ -0,0 +1,49 @@
+[
+ {
+ "description": "minLength validation",
+ "schema": {"minLength": 2},
+ "tests": [
+ {
+ "description": "longer is valid",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "exact length is valid",
+ "data": "fo",
+ "valid": true
+ },
+ {
+ "description": "too short is invalid",
+ "data": "f",
+ "valid": false
+ },
+ {
+ "description": "ignores non-strings",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "one supplementary Unicode code point is not long enough",
+ "data": "\uD83D\uDCA9",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "minLength validation with a decimal",
+ "schema": {"minLength": 2.0},
+ "tests": [
+ {
+ "description": "longer is valid",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "too short is invalid",
+ "data": "f",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/minProperties.json b/tests/draft7/minProperties.json
new file mode 100644
index 0000000..9f74f78
--- /dev/null
+++ b/tests/draft7/minProperties.json
@@ -0,0 +1,54 @@
+[
+ {
+ "description": "minProperties validation",
+ "schema": {"minProperties": 1},
+ "tests": [
+ {
+ "description": "longer is valid",
+ "data": {"foo": 1, "bar": 2},
+ "valid": true
+ },
+ {
+ "description": "exact length is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "too short is invalid",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "ignores arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "ignores strings",
+ "data": "",
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "minProperties validation with a decimal",
+ "schema": {"minProperties": 1.0},
+ "tests": [
+ {
+ "description": "longer is valid",
+ "data": {"foo": 1, "bar": 2},
+ "valid": true
+ },
+ {
+ "description": "too short is invalid",
+ "data": {},
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/minimum.json b/tests/draft7/minimum.json
new file mode 100644
index 0000000..21ae50e
--- /dev/null
+++ b/tests/draft7/minimum.json
@@ -0,0 +1,69 @@
+[
+ {
+ "description": "minimum validation",
+ "schema": {"minimum": 1.1},
+ "tests": [
+ {
+ "description": "above the minimum is valid",
+ "data": 2.6,
+ "valid": true
+ },
+ {
+ "description": "boundary point is valid",
+ "data": 1.1,
+ "valid": true
+ },
+ {
+ "description": "below the minimum is invalid",
+ "data": 0.6,
+ "valid": false
+ },
+ {
+ "description": "ignores non-numbers",
+ "data": "x",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "minimum validation with signed integer",
+ "schema": {"minimum": -2},
+ "tests": [
+ {
+ "description": "negative above the minimum is valid",
+ "data": -1,
+ "valid": true
+ },
+ {
+ "description": "positive above the minimum is valid",
+ "data": 0,
+ "valid": true
+ },
+ {
+ "description": "boundary point is valid",
+ "data": -2,
+ "valid": true
+ },
+ {
+ "description": "boundary point with float is valid",
+ "data": -2.0,
+ "valid": true
+ },
+ {
+ "description": "float below the minimum is invalid",
+ "data": -2.0001,
+ "valid": false
+ },
+ {
+ "description": "int below the minimum is invalid",
+ "data": -3,
+ "valid": false
+ },
+ {
+ "description": "ignores non-numbers",
+ "data": "x",
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/multipleOf.json b/tests/draft7/multipleOf.json
new file mode 100644
index 0000000..25c25a9
--- /dev/null
+++ b/tests/draft7/multipleOf.json
@@ -0,0 +1,71 @@
+[
+ {
+ "description": "by int",
+ "schema": {"multipleOf": 2},
+ "tests": [
+ {
+ "description": "int by int",
+ "data": 10,
+ "valid": true
+ },
+ {
+ "description": "int by int fail",
+ "data": 7,
+ "valid": false
+ },
+ {
+ "description": "ignores non-numbers",
+ "data": "foo",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "by number",
+ "schema": {"multipleOf": 1.5},
+ "tests": [
+ {
+ "description": "zero is multiple of anything",
+ "data": 0,
+ "valid": true
+ },
+ {
+ "description": "4.5 is multiple of 1.5",
+ "data": 4.5,
+ "valid": true
+ },
+ {
+ "description": "35 is not multiple of 1.5",
+ "data": 35,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "by small number",
+ "schema": {"multipleOf": 0.0001},
+ "tests": [
+ {
+ "description": "0.0075 is multiple of 0.0001",
+ "data": 0.0075,
+ "valid": true
+ },
+ {
+ "description": "0.00751 is not multiple of 0.0001",
+ "data": 0.00751,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "float division = inf",
+ "schema": {"type": "integer", "multipleOf": 0.123456789},
+ "tests": [
+ {
+ "description": "always invalid, but naive implementations may raise an overflow error",
+ "data": 1e308,
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/not.json b/tests/draft7/not.json
new file mode 100644
index 0000000..98de0ed
--- /dev/null
+++ b/tests/draft7/not.json
@@ -0,0 +1,117 @@
+[
+ {
+ "description": "not",
+ "schema": {
+ "not": {"type": "integer"}
+ },
+ "tests": [
+ {
+ "description": "allowed",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "disallowed",
+ "data": 1,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "not multiple types",
+ "schema": {
+ "not": {"type": ["integer", "boolean"]}
+ },
+ "tests": [
+ {
+ "description": "valid",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "mismatch",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "other mismatch",
+ "data": true,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "not more complex schema",
+ "schema": {
+ "not": {
+ "type": "object",
+ "properties": {
+ "foo": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "match",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "other match",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "mismatch",
+ "data": {"foo": "bar"},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "forbidden property",
+ "schema": {
+ "properties": {
+ "foo": {
+ "not": {}
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "property present",
+ "data": {"foo": 1, "bar": 2},
+ "valid": false
+ },
+ {
+ "description": "property absent",
+ "data": {"bar": 1, "baz": 2},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "not with boolean schema true",
+ "schema": {"not": true},
+ "tests": [
+ {
+ "description": "any value is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "not with boolean schema false",
+ "schema": {"not": false},
+ "tests": [
+ {
+ "description": "any value is valid",
+ "data": "foo",
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/oneOf.json b/tests/draft7/oneOf.json
new file mode 100644
index 0000000..eeb7ae8
--- /dev/null
+++ b/tests/draft7/oneOf.json
@@ -0,0 +1,274 @@
+[
+ {
+ "description": "oneOf",
+ "schema": {
+ "oneOf": [
+ {
+ "type": "integer"
+ },
+ {
+ "minimum": 2
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "first oneOf valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "second oneOf valid",
+ "data": 2.5,
+ "valid": true
+ },
+ {
+ "description": "both oneOf valid",
+ "data": 3,
+ "valid": false
+ },
+ {
+ "description": "neither oneOf valid",
+ "data": 1.5,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "oneOf with base schema",
+ "schema": {
+ "type": "string",
+ "oneOf" : [
+ {
+ "minLength": 2
+ },
+ {
+ "maxLength": 4
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "mismatch base schema",
+ "data": 3,
+ "valid": false
+ },
+ {
+ "description": "one oneOf valid",
+ "data": "foobar",
+ "valid": true
+ },
+ {
+ "description": "both oneOf valid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "oneOf with boolean schemas, all true",
+ "schema": {"oneOf": [true, true, true]},
+ "tests": [
+ {
+ "description": "any value is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "oneOf with boolean schemas, one true",
+ "schema": {"oneOf": [true, false, false]},
+ "tests": [
+ {
+ "description": "any value is valid",
+ "data": "foo",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "oneOf with boolean schemas, more than one true",
+ "schema": {"oneOf": [true, true, false]},
+ "tests": [
+ {
+ "description": "any value is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "oneOf with boolean schemas, all false",
+ "schema": {"oneOf": [false, false, false]},
+ "tests": [
+ {
+ "description": "any value is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "oneOf complex types",
+ "schema": {
+ "oneOf": [
+ {
+ "properties": {
+ "bar": {"type": "integer"}
+ },
+ "required": ["bar"]
+ },
+ {
+ "properties": {
+ "foo": {"type": "string"}
+ },
+ "required": ["foo"]
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "first oneOf valid (complex)",
+ "data": {"bar": 2},
+ "valid": true
+ },
+ {
+ "description": "second oneOf valid (complex)",
+ "data": {"foo": "baz"},
+ "valid": true
+ },
+ {
+ "description": "both oneOf valid (complex)",
+ "data": {"foo": "baz", "bar": 2},
+ "valid": false
+ },
+ {
+ "description": "neither oneOf valid (complex)",
+ "data": {"foo": 2, "bar": "quux"},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "oneOf with empty schema",
+ "schema": {
+ "oneOf": [
+ { "type": "number" },
+ {}
+ ]
+ },
+ "tests": [
+ {
+ "description": "one valid - valid",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "both valid - invalid",
+ "data": 123,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "oneOf with required",
+ "schema": {
+ "type": "object",
+ "oneOf": [
+ { "required": ["foo", "bar"] },
+ { "required": ["foo", "baz"] }
+ ]
+ },
+ "tests": [
+ {
+ "description": "both invalid - invalid",
+ "data": {"bar": 2},
+ "valid": false
+ },
+ {
+ "description": "first valid - valid",
+ "data": {"foo": 1, "bar": 2},
+ "valid": true
+ },
+ {
+ "description": "second valid - valid",
+ "data": {"foo": 1, "baz": 3},
+ "valid": true
+ },
+ {
+ "description": "both valid - invalid",
+ "data": {"foo": 1, "bar": 2, "baz" : 3},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "oneOf with missing optional property",
+ "schema": {
+ "oneOf": [
+ {
+ "properties": {
+ "bar": true,
+ "baz": true
+ },
+ "required": ["bar"]
+ },
+ {
+ "properties": {
+ "foo": true
+ },
+ "required": ["foo"]
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "first oneOf valid",
+ "data": {"bar": 8},
+ "valid": true
+ },
+ {
+ "description": "second oneOf valid",
+ "data": {"foo": "foo"},
+ "valid": true
+ },
+ {
+ "description": "both oneOf valid",
+ "data": {"foo": "foo", "bar": 8},
+ "valid": false
+ },
+ {
+ "description": "neither oneOf valid",
+ "data": {"baz": "quux"},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "nested oneOf, to check validation semantics",
+ "schema": {
+ "oneOf": [
+ {
+ "oneOf": [
+ {
+ "type": "null"
+ }
+ ]
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "null is valid",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "anything non-null is invalid",
+ "data": 123,
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/bignum.json b/tests/draft7/optional/bignum.json
new file mode 100644
index 0000000..94b4a4e
--- /dev/null
+++ b/tests/draft7/optional/bignum.json
@@ -0,0 +1,93 @@
+[
+ {
+ "description": "integer",
+ "schema": { "type": "integer" },
+ "tests": [
+ {
+ "description": "a bignum is an integer",
+ "data": 12345678910111213141516171819202122232425262728293031,
+ "valid": true
+ },
+ {
+ "description": "a negative bignum is an integer",
+ "data": -12345678910111213141516171819202122232425262728293031,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "number",
+ "schema": { "type": "number" },
+ "tests": [
+ {
+ "description": "a bignum is a number",
+ "data": 98249283749234923498293171823948729348710298301928331,
+ "valid": true
+ },
+ {
+ "description": "a negative bignum is a number",
+ "data": -98249283749234923498293171823948729348710298301928331,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "string",
+ "schema": { "type": "string" },
+ "tests": [
+ {
+ "description": "a bignum is not a string",
+ "data": 98249283749234923498293171823948729348710298301928331,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "maximum integer comparison",
+ "schema": { "maximum": 18446744073709551615 },
+ "tests": [
+ {
+ "description": "comparison works for high numbers",
+ "data": 18446744073709551600,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "float comparison with high precision",
+ "schema": {
+ "exclusiveMaximum": 972783798187987123879878123.18878137
+ },
+ "tests": [
+ {
+ "description": "comparison works for high numbers",
+ "data": 972783798187987123879878123.188781371,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "minimum integer comparison",
+ "schema": { "minimum": -18446744073709551615 },
+ "tests": [
+ {
+ "description": "comparison works for very negative numbers",
+ "data": -18446744073709551600,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "float comparison with high precision on negative numbers",
+ "schema": {
+ "exclusiveMinimum": -972783798187987123879878123.18878137
+ },
+ "tests": [
+ {
+ "description": "comparison works for very negative numbers",
+ "data": -972783798187987123879878123.188781371,
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/content.json b/tests/draft7/optional/content.json
new file mode 100644
index 0000000..3f5a743
--- /dev/null
+++ b/tests/draft7/optional/content.json
@@ -0,0 +1,77 @@
+[
+ {
+ "description": "validation of string-encoded content based on media type",
+ "schema": {
+ "contentMediaType": "application/json"
+ },
+ "tests": [
+ {
+ "description": "a valid JSON document",
+ "data": "{\"foo\": \"bar\"}",
+ "valid": true
+ },
+ {
+ "description": "an invalid JSON document",
+ "data": "{:}",
+ "valid": false
+ },
+ {
+ "description": "ignores non-strings",
+ "data": 100,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "validation of binary string-encoding",
+ "schema": {
+ "contentEncoding": "base64"
+ },
+ "tests": [
+ {
+ "description": "a valid base64 string",
+ "data": "eyJmb28iOiAiYmFyIn0K",
+ "valid": true
+ },
+ {
+ "description": "an invalid base64 string (% is not a valid character)",
+ "data": "eyJmb28iOi%iYmFyIn0K",
+ "valid": false
+ },
+ {
+ "description": "ignores non-strings",
+ "data": 100,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "validation of binary-encoded media type documents",
+ "schema": {
+ "contentMediaType": "application/json",
+ "contentEncoding": "base64"
+ },
+ "tests": [
+ {
+ "description": "a valid base64-encoded JSON document",
+ "data": "eyJmb28iOiAiYmFyIn0K",
+ "valid": true
+ },
+ {
+ "description": "a validly-encoded invalid JSON document",
+ "data": "ezp9Cg==",
+ "valid": false
+ },
+ {
+ "description": "an invalid base64 string that is valid JSON",
+ "data": "{}",
+ "valid": false
+ },
+ {
+ "description": "ignores non-strings",
+ "data": 100,
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/cross-draft.json b/tests/draft7/optional/cross-draft.json
new file mode 100644
index 0000000..8ff5373
--- /dev/null
+++ b/tests/draft7/optional/cross-draft.json
@@ -0,0 +1,25 @@
+[
+ {
+ "description": "refs to future drafts are processed as future drafts",
+ "schema": {
+ "type": "object",
+ "allOf": [
+ { "properties": { "foo": true } },
+ { "$ref": "http://localhost:1234/draft2019-09/dependentRequired.json" }
+ ]
+ },
+ "tests": [
+ {
+ "description": "missing bar is invalid",
+ "comment": "if the implementation is not processing the $ref as a 2019-09 schema, this test will fail",
+ "data": {"foo": "any value"},
+ "valid": false
+ },
+ {
+ "description": "present bar is valid",
+ "data": {"foo": "any value", "bar": "also any value"},
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/ecmascript-regex.json b/tests/draft7/optional/ecmascript-regex.json
new file mode 100644
index 0000000..c4886aa
--- /dev/null
+++ b/tests/draft7/optional/ecmascript-regex.json
@@ -0,0 +1,552 @@
+[
+ {
+ "description": "ECMA 262 regex $ does not match trailing newline",
+ "schema": {
+ "type": "string",
+ "pattern": "^abc$"
+ },
+ "tests": [
+ {
+ "description": "matches in Python, but not in ECMA 262",
+ "data": "abc\\n",
+ "valid": false
+ },
+ {
+ "description": "matches",
+ "data": "abc",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ECMA 262 regex converts \\t to horizontal tab",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\t$"
+ },
+ "tests": [
+ {
+ "description": "does not match",
+ "data": "\\t",
+ "valid": false
+ },
+ {
+ "description": "matches",
+ "data": "\u0009",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ECMA 262 regex escapes control codes with \\c and upper letter",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\cC$"
+ },
+ "tests": [
+ {
+ "description": "does not match",
+ "data": "\\cC",
+ "valid": false
+ },
+ {
+ "description": "matches",
+ "data": "\u0003",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ECMA 262 regex escapes control codes with \\c and lower letter",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\cc$"
+ },
+ "tests": [
+ {
+ "description": "does not match",
+ "data": "\\cc",
+ "valid": false
+ },
+ {
+ "description": "matches",
+ "data": "\u0003",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ECMA 262 \\d matches ascii digits only",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\d$"
+ },
+ "tests": [
+ {
+ "description": "ASCII zero matches",
+ "data": "0",
+ "valid": true
+ },
+ {
+ "description": "NKO DIGIT ZERO does not match (unlike e.g. Python)",
+ "data": "߀",
+ "valid": false
+ },
+ {
+ "description": "NKO DIGIT ZERO (as \\u escape) does not match",
+ "data": "\u07c0",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "ECMA 262 \\D matches everything but ascii digits",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\D$"
+ },
+ "tests": [
+ {
+ "description": "ASCII zero does not match",
+ "data": "0",
+ "valid": false
+ },
+ {
+ "description": "NKO DIGIT ZERO matches (unlike e.g. Python)",
+ "data": "߀",
+ "valid": true
+ },
+ {
+ "description": "NKO DIGIT ZERO (as \\u escape) matches",
+ "data": "\u07c0",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ECMA 262 \\w matches ascii letters only",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\w$"
+ },
+ "tests": [
+ {
+ "description": "ASCII 'a' matches",
+ "data": "a",
+ "valid": true
+ },
+ {
+ "description": "latin-1 e-acute does not match (unlike e.g. Python)",
+ "data": "é",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "ECMA 262 \\W matches everything but ascii letters",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\W$"
+ },
+ "tests": [
+ {
+ "description": "ASCII 'a' does not match",
+ "data": "a",
+ "valid": false
+ },
+ {
+ "description": "latin-1 e-acute matches (unlike e.g. Python)",
+ "data": "é",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ECMA 262 \\s matches whitespace",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\s$"
+ },
+ "tests": [
+ {
+ "description": "ASCII space matches",
+ "data": " ",
+ "valid": true
+ },
+ {
+ "description": "Character tabulation matches",
+ "data": "\t",
+ "valid": true
+ },
+ {
+ "description": "Line tabulation matches",
+ "data": "\u000b",
+ "valid": true
+ },
+ {
+ "description": "Form feed matches",
+ "data": "\u000c",
+ "valid": true
+ },
+ {
+ "description": "latin-1 non-breaking-space matches",
+ "data": "\u00a0",
+ "valid": true
+ },
+ {
+ "description": "zero-width whitespace matches",
+ "data": "\ufeff",
+ "valid": true
+ },
+ {
+ "description": "line feed matches (line terminator)",
+ "data": "\u000a",
+ "valid": true
+ },
+ {
+ "description": "paragraph separator matches (line terminator)",
+ "data": "\u2029",
+ "valid": true
+ },
+ {
+ "description": "EM SPACE matches (Space_Separator)",
+ "data": "\u2003",
+ "valid": true
+ },
+ {
+ "description": "Non-whitespace control does not match",
+ "data": "\u0001",
+ "valid": false
+ },
+ {
+ "description": "Non-whitespace does not match",
+ "data": "\u2013",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "ECMA 262 \\S matches everything but whitespace",
+ "schema": {
+ "type": "string",
+ "pattern": "^\\S$"
+ },
+ "tests": [
+ {
+ "description": "ASCII space does not match",
+ "data": " ",
+ "valid": false
+ },
+ {
+ "description": "Character tabulation does not match",
+ "data": "\t",
+ "valid": false
+ },
+ {
+ "description": "Line tabulation does not match",
+ "data": "\u000b",
+ "valid": false
+ },
+ {
+ "description": "Form feed does not match",
+ "data": "\u000c",
+ "valid": false
+ },
+ {
+ "description": "latin-1 non-breaking-space does not match",
+ "data": "\u00a0",
+ "valid": false
+ },
+ {
+ "description": "zero-width whitespace does not match",
+ "data": "\ufeff",
+ "valid": false
+ },
+ {
+ "description": "line feed does not match (line terminator)",
+ "data": "\u000a",
+ "valid": false
+ },
+ {
+ "description": "paragraph separator does not match (line terminator)",
+ "data": "\u2029",
+ "valid": false
+ },
+ {
+ "description": "EM SPACE does not match (Space_Separator)",
+ "data": "\u2003",
+ "valid": false
+ },
+ {
+ "description": "Non-whitespace control matches",
+ "data": "\u0001",
+ "valid": true
+ },
+ {
+ "description": "Non-whitespace matches",
+ "data": "\u2013",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "patterns always use unicode semantics with pattern",
+ "schema": { "pattern": "\\p{Letter}cole" },
+ "tests": [
+ {
+ "description": "ascii character in json string",
+ "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.",
+ "valid": true
+ },
+ {
+ "description": "literal unicode character in json string",
+ "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
+ "valid": true
+ },
+ {
+ "description": "unicode character in hex format in string",
+ "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
+ "valid": true
+ },
+ {
+ "description": "unicode matching is case-sensitive",
+ "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters",
+ "schema": { "pattern": "\\wcole" },
+ "tests": [
+ {
+ "description": "ascii character in json string",
+ "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.",
+ "valid": true
+ },
+ {
+ "description": "literal unicode character in json string",
+ "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
+ "valid": false
+ },
+ {
+ "description": "unicode character in hex format in string",
+ "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
+ "valid": false
+ },
+ {
+ "description": "unicode matching is case-sensitive",
+ "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "pattern with ASCII ranges",
+ "schema": { "pattern": "[a-z]cole" },
+ "tests": [
+ {
+ "description": "literal unicode character in json string",
+ "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
+ "valid": false
+ },
+ {
+ "description": "unicode character in hex format in string",
+ "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.",
+ "valid": false
+ },
+ {
+ "description": "ascii characters match",
+ "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "\\d in pattern matches [0-9], not unicode digits",
+ "schema": { "pattern": "^\\d+$" },
+ "tests": [
+ {
+ "description": "ascii digits",
+ "data": "42",
+ "valid": true
+ },
+ {
+ "description": "ascii non-digits",
+ "data": "-%#",
+ "valid": false
+ },
+ {
+ "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
+ "data": "৪২",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "pattern with non-ASCII digits",
+ "schema": { "pattern": "^\\p{digit}+$" },
+ "tests": [
+ {
+ "description": "ascii digits",
+ "data": "42",
+ "valid": true
+ },
+ {
+ "description": "ascii non-digits",
+ "data": "-%#",
+ "valid": false
+ },
+ {
+ "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
+ "data": "৪২",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "patterns always use unicode semantics with patternProperties",
+ "schema": {
+ "type": "object",
+ "patternProperties": {
+ "\\p{Letter}cole": true
+ },
+ "additionalProperties": false
+ },
+ "tests": [
+ {
+ "description": "ascii character in json string",
+ "data": { "l'ecole": "pas de vraie vie" },
+ "valid": true
+ },
+ {
+ "description": "literal unicode character in json string",
+ "data": { "l'école": "pas de vraie vie" },
+ "valid": true
+ },
+ {
+ "description": "unicode character in hex format in string",
+ "data": { "l'\u00e9cole": "pas de vraie vie" },
+ "valid": true
+ },
+ {
+ "description": "unicode matching is case-sensitive",
+ "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters",
+ "schema": {
+ "type": "object",
+ "patternProperties": {
+ "\\wcole": true
+ },
+ "additionalProperties": false
+ },
+ "tests": [
+ {
+ "description": "ascii character in json string",
+ "data": { "l'ecole": "pas de vraie vie" },
+ "valid": true
+ },
+ {
+ "description": "literal unicode character in json string",
+ "data": { "l'école": "pas de vraie vie" },
+ "valid": false
+ },
+ {
+ "description": "unicode character in hex format in string",
+ "data": { "l'\u00e9cole": "pas de vraie vie" },
+ "valid": false
+ },
+ {
+ "description": "unicode matching is case-sensitive",
+ "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "patternProperties with ASCII ranges",
+ "schema": {
+ "type": "object",
+ "patternProperties": {
+ "[a-z]cole": true
+ },
+ "additionalProperties": false
+ },
+ "tests": [
+ {
+ "description": "literal unicode character in json string",
+ "data": { "l'école": "pas de vraie vie" },
+ "valid": false
+ },
+ {
+ "description": "unicode character in hex format in string",
+ "data": { "l'\u00e9cole": "pas de vraie vie" },
+ "valid": false
+ },
+ {
+ "description": "ascii characters match",
+ "data": { "l'ecole": "pas de vraie vie" },
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "\\d in patternProperties matches [0-9], not unicode digits",
+ "schema": {
+ "type": "object",
+ "patternProperties": {
+ "^\\d+$": true
+ },
+ "additionalProperties": false
+ },
+ "tests": [
+ {
+ "description": "ascii digits",
+ "data": { "42": "life, the universe, and everything" },
+ "valid": true
+ },
+ {
+ "description": "ascii non-digits",
+ "data": { "-%#": "spending the year dead for tax reasons" },
+ "valid": false
+ },
+ {
+ "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
+ "data": { "৪২": "khajit has wares if you have coin" },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "patternProperties with non-ASCII digits",
+ "schema": {
+ "type": "object",
+ "patternProperties": {
+ "^\\p{digit}+$": true
+ },
+ "additionalProperties": false
+ },
+ "tests": [
+ {
+ "description": "ascii digits",
+ "data": { "42": "life, the universe, and everything" },
+ "valid": true
+ },
+ {
+ "description": "ascii non-digits",
+ "data": { "-%#": "spending the year dead for tax reasons" },
+ "valid": false
+ },
+ {
+ "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)",
+ "data": { "৪২": "khajit has wares if you have coin" },
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/float-overflow.json b/tests/draft7/optional/float-overflow.json
new file mode 100644
index 0000000..52ff982
--- /dev/null
+++ b/tests/draft7/optional/float-overflow.json
@@ -0,0 +1,13 @@
+[
+ {
+ "description": "all integers are multiples of 0.5, if overflow is handled",
+ "schema": {"type": "integer", "multipleOf": 0.5},
+ "tests": [
+ {
+ "description": "valid if optional overflow handling is implemented",
+ "data": 1e308,
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/date-time.json b/tests/draft7/optional/format/date-time.json
new file mode 100644
index 0000000..0911273
--- /dev/null
+++ b/tests/draft7/optional/format/date-time.json
@@ -0,0 +1,133 @@
+[
+ {
+ "description": "validation of date-time strings",
+ "schema": { "format": "date-time" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid date-time string",
+ "data": "1963-06-19T08:30:06.283185Z",
+ "valid": true
+ },
+ {
+ "description": "a valid date-time string without second fraction",
+ "data": "1963-06-19T08:30:06Z",
+ "valid": true
+ },
+ {
+ "description": "a valid date-time string with plus offset",
+ "data": "1937-01-01T12:00:27.87+00:20",
+ "valid": true
+ },
+ {
+ "description": "a valid date-time string with minus offset",
+ "data": "1990-12-31T15:59:50.123-08:00",
+ "valid": true
+ },
+ {
+ "description": "a valid date-time with a leap second, UTC",
+ "data": "1998-12-31T23:59:60Z",
+ "valid": true
+ },
+ {
+ "description": "a valid date-time with a leap second, with minus offset",
+ "data": "1998-12-31T15:59:60.123-08:00",
+ "valid": true
+ },
+ {
+ "description": "an invalid date-time past leap second, UTC",
+ "data": "1998-12-31T23:59:61Z",
+ "valid": false
+ },
+ {
+ "description": "an invalid date-time with leap second on a wrong minute, UTC",
+ "data": "1998-12-31T23:58:60Z",
+ "valid": false
+ },
+ {
+ "description": "an invalid date-time with leap second on a wrong hour, UTC",
+ "data": "1998-12-31T22:59:60Z",
+ "valid": false
+ },
+ {
+ "description": "an invalid day in date-time string",
+ "data": "1990-02-31T15:59:59.123-08:00",
+ "valid": false
+ },
+ {
+ "description": "an invalid offset in date-time string",
+ "data": "1990-12-31T15:59:59-24:00",
+ "valid": false
+ },
+ {
+ "description": "an invalid closing Z after time-zone offset",
+ "data": "1963-06-19T08:30:06.28123+01:00Z",
+ "valid": false
+ },
+ {
+ "description": "an invalid date-time string",
+ "data": "06/19/1963 08:30:06 PST",
+ "valid": false
+ },
+ {
+ "description": "case-insensitive T and Z",
+ "data": "1963-06-19t08:30:06.283185z",
+ "valid": true
+ },
+ {
+ "description": "only RFC3339 not all of ISO 8601 are valid",
+ "data": "2013-350T01:01:01",
+ "valid": false
+ },
+ {
+ "description": "invalid non-padded month dates",
+ "data": "1963-6-19T08:30:06.283185Z",
+ "valid": false
+ },
+ {
+ "description": "invalid non-padded day dates",
+ "data": "1963-06-1T08:30:06.283185Z",
+ "valid": false
+ },
+ {
+ "description": "invalid non-ASCII '৪' (a Bengali 4) in date portion",
+ "data": "1963-06-1৪T00:00:00Z",
+ "valid": false
+ },
+ {
+ "description": "invalid non-ASCII '৪' (a Bengali 4) in time portion",
+ "data": "1963-06-11T0৪:00:00Z",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/date.json b/tests/draft7/optional/format/date.json
new file mode 100644
index 0000000..06c9ea0
--- /dev/null
+++ b/tests/draft7/optional/format/date.json
@@ -0,0 +1,223 @@
+[
+ {
+ "description": "validation of date strings",
+ "schema": { "format": "date" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid date string",
+ "data": "1963-06-19",
+ "valid": true
+ },
+ {
+ "description": "a valid date string with 31 days in January",
+ "data": "2020-01-31",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 32 days in January",
+ "data": "2020-01-32",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 28 days in February (normal)",
+ "data": "2021-02-28",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 29 days in February (normal)",
+ "data": "2021-02-29",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 29 days in February (leap)",
+ "data": "2020-02-29",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 30 days in February (leap)",
+ "data": "2020-02-30",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 31 days in March",
+ "data": "2020-03-31",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 32 days in March",
+ "data": "2020-03-32",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 30 days in April",
+ "data": "2020-04-30",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 31 days in April",
+ "data": "2020-04-31",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 31 days in May",
+ "data": "2020-05-31",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 32 days in May",
+ "data": "2020-05-32",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 30 days in June",
+ "data": "2020-06-30",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 31 days in June",
+ "data": "2020-06-31",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 31 days in July",
+ "data": "2020-07-31",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 32 days in July",
+ "data": "2020-07-32",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 31 days in August",
+ "data": "2020-08-31",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 32 days in August",
+ "data": "2020-08-32",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 30 days in September",
+ "data": "2020-09-30",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 31 days in September",
+ "data": "2020-09-31",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 31 days in October",
+ "data": "2020-10-31",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 32 days in October",
+ "data": "2020-10-32",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 30 days in November",
+ "data": "2020-11-30",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 31 days in November",
+ "data": "2020-11-31",
+ "valid": false
+ },
+ {
+ "description": "a valid date string with 31 days in December",
+ "data": "2020-12-31",
+ "valid": true
+ },
+ {
+ "description": "a invalid date string with 32 days in December",
+ "data": "2020-12-32",
+ "valid": false
+ },
+ {
+ "description": "a invalid date string with invalid month",
+ "data": "2020-13-01",
+ "valid": false
+ },
+ {
+ "description": "an invalid date string",
+ "data": "06/19/1963",
+ "valid": false
+ },
+ {
+ "description": "only RFC3339 not all of ISO 8601 are valid",
+ "data": "2013-350",
+ "valid": false
+ },
+ {
+ "description": "non-padded month dates are not valid",
+ "data": "1998-1-20",
+ "valid": false
+ },
+ {
+ "description": "non-padded day dates are not valid",
+ "data": "1998-01-1",
+ "valid": false
+ },
+ {
+ "description": "invalid month",
+ "data": "1998-13-01",
+ "valid": false
+ },
+ {
+ "description": "invalid month-day combination",
+ "data": "1998-04-31",
+ "valid": false
+ },
+ {
+ "description": "2021 is not a leap year",
+ "data": "2021-02-29",
+ "valid": false
+ },
+ {
+ "description": "2020 is a leap year",
+ "data": "2020-02-29",
+ "valid": true
+ },
+ {
+ "description": "invalid non-ASCII '৪' (a Bengali 4)",
+ "data": "1963-06-1৪",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/email.json b/tests/draft7/optional/format/email.json
new file mode 100644
index 0000000..d6761a4
--- /dev/null
+++ b/tests/draft7/optional/format/email.json
@@ -0,0 +1,83 @@
+[
+ {
+ "description": "validation of e-mail addresses",
+ "schema": { "format": "email" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid e-mail address",
+ "data": "joe.bloggs@example.com",
+ "valid": true
+ },
+ {
+ "description": "an invalid e-mail address",
+ "data": "2962",
+ "valid": false
+ },
+ {
+ "description": "tilde in local part is valid",
+ "data": "te~st@example.com",
+ "valid": true
+ },
+ {
+ "description": "tilde before local part is valid",
+ "data": "~test@example.com",
+ "valid": true
+ },
+ {
+ "description": "tilde after local part is valid",
+ "data": "test~@example.com",
+ "valid": true
+ },
+ {
+ "description": "dot before local part is not valid",
+ "data": ".test@example.com",
+ "valid": false
+ },
+ {
+ "description": "dot after local part is not valid",
+ "data": "test.@example.com",
+ "valid": false
+ },
+ {
+ "description": "two separated dots inside local part are valid",
+ "data": "te.s.t@example.com",
+ "valid": true
+ },
+ {
+ "description": "two subsequent dots inside local part are not valid",
+ "data": "te..st@example.com",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/hostname.json b/tests/draft7/optional/format/hostname.json
new file mode 100644
index 0000000..8a67fda
--- /dev/null
+++ b/tests/draft7/optional/format/hostname.json
@@ -0,0 +1,98 @@
+[
+ {
+ "description": "validation of host names",
+ "schema": { "format": "hostname" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid host name",
+ "data": "www.example.com",
+ "valid": true
+ },
+ {
+ "description": "a valid punycoded IDN hostname",
+ "data": "xn--4gbwdl.xn--wgbh1c",
+ "valid": true
+ },
+ {
+ "description": "a host name starting with an illegal character",
+ "data": "-a-host-name-that-starts-with--",
+ "valid": false
+ },
+ {
+ "description": "a host name containing illegal characters",
+ "data": "not_a_valid_host_name",
+ "valid": false
+ },
+ {
+ "description": "a host name with a component too long",
+ "data": "a-vvvvvvvvvvvvvvvveeeeeeeeeeeeeeeerrrrrrrrrrrrrrrryyyyyyyyyyyyyyyy-long-host-name-component",
+ "valid": false
+ },
+ {
+ "description": "starts with hyphen",
+ "data": "-hostname",
+ "valid": false
+ },
+ {
+ "description": "ends with hyphen",
+ "data": "hostname-",
+ "valid": false
+ },
+ {
+ "description": "starts with underscore",
+ "data": "_hostname",
+ "valid": false
+ },
+ {
+ "description": "ends with underscore",
+ "data": "hostname_",
+ "valid": false
+ },
+ {
+ "description": "contains underscore",
+ "data": "host_name",
+ "valid": false
+ },
+ {
+ "description": "maximum label length",
+ "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com",
+ "valid": true
+ },
+ {
+ "description": "exceeds maximum label length",
+ "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/idn-email.json b/tests/draft7/optional/format/idn-email.json
new file mode 100644
index 0000000..6e21374
--- /dev/null
+++ b/tests/draft7/optional/format/idn-email.json
@@ -0,0 +1,58 @@
+[
+ {
+ "description": "validation of an internationalized e-mail addresses",
+ "schema": { "format": "idn-email" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid idn e-mail (example@example.test in Hangul)",
+ "data": "실례@실례.테스트",
+ "valid": true
+ },
+ {
+ "description": "an invalid idn e-mail address",
+ "data": "2962",
+ "valid": false
+ },
+ {
+ "description": "a valid e-mail address",
+ "data": "joe.bloggs@example.com",
+ "valid": true
+ },
+ {
+ "description": "an invalid e-mail address",
+ "data": "2962",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/idn-hostname.json b/tests/draft7/optional/format/idn-hostname.json
new file mode 100644
index 0000000..6c8f86a
--- /dev/null
+++ b/tests/draft7/optional/format/idn-hostname.json
@@ -0,0 +1,304 @@
+[
+ {
+ "description": "validation of internationalized host names",
+ "schema": { "format": "idn-hostname" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid host name (example.test in Hangul)",
+ "data": "실례.테스트",
+ "valid": true
+ },
+ {
+ "description": "illegal first char U+302E Hangul single dot tone mark",
+ "data": "〮실례.테스트",
+ "valid": false
+ },
+ {
+ "description": "contains illegal char U+302E Hangul single dot tone mark",
+ "data": "실〮례.테스트",
+ "valid": false
+ },
+ {
+ "description": "a host name with a component too long",
+ "data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트",
+ "valid": false
+ },
+ {
+ "description": "invalid label, correct Punycode",
+ "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc3492#section-7.1",
+ "data": "-> $1.00 <--",
+ "valid": false
+ },
+ {
+ "description": "valid Chinese Punycode",
+ "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4",
+ "data": "xn--ihqwcrb4cv8a8dqg056pqjye",
+ "valid": true
+ },
+ {
+ "description": "invalid Punycode",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc5890#section-2.3.2.1",
+ "data": "xn--X",
+ "valid": false
+ },
+ {
+ "description": "U-label contains \"--\" in the 3rd and 4th position",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1 https://tools.ietf.org/html/rfc5890#section-2.3.2.1",
+ "data": "XN--aa---o47jg78q",
+ "valid": false
+ },
+ {
+ "description": "U-label starts with a dash",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1",
+ "data": "-hello",
+ "valid": false
+ },
+ {
+ "description": "U-label ends with a dash",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1",
+ "data": "hello-",
+ "valid": false
+ },
+ {
+ "description": "U-label starts and ends with a dash",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1",
+ "data": "-hello-",
+ "valid": false
+ },
+ {
+ "description": "Begins with a Spacing Combining Mark",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2",
+ "data": "\u0903hello",
+ "valid": false
+ },
+ {
+ "description": "Begins with a Nonspacing Mark",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2",
+ "data": "\u0300hello",
+ "valid": false
+ },
+ {
+ "description": "Begins with an Enclosing Mark",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2",
+ "data": "\u0488hello",
+ "valid": false
+ },
+ {
+ "description": "Exceptions that are PVALID, left-to-right chars",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6",
+ "data": "\u00df\u03c2\u0f0b\u3007",
+ "valid": true
+ },
+ {
+ "description": "Exceptions that are PVALID, right-to-left chars",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6",
+ "data": "\u06fd\u06fe",
+ "valid": true
+ },
+ {
+ "description": "Exceptions that are DISALLOWED, right-to-left chars",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6",
+ "data": "\u0640\u07fa",
+ "valid": false
+ },
+ {
+ "description": "Exceptions that are DISALLOWED, left-to-right chars",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6 Note: The two combining marks (U+302E and U+302F) are in the middle and not at the start",
+ "data": "\u3031\u3032\u3033\u3034\u3035\u302e\u302f\u303b",
+ "valid": false
+ },
+ {
+ "description": "MIDDLE DOT with no preceding 'l'",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
+ "data": "a\u00b7l",
+ "valid": false
+ },
+ {
+ "description": "MIDDLE DOT with nothing preceding",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
+ "data": "\u00b7l",
+ "valid": false
+ },
+ {
+ "description": "MIDDLE DOT with no following 'l'",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
+ "data": "l\u00b7a",
+ "valid": false
+ },
+ {
+ "description": "MIDDLE DOT with nothing following",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
+ "data": "l\u00b7",
+ "valid": false
+ },
+ {
+ "description": "MIDDLE DOT with surrounding 'l's",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3",
+ "data": "l\u00b7l",
+ "valid": true
+ },
+ {
+ "description": "Greek KERAIA not followed by Greek",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4",
+ "data": "\u03b1\u0375S",
+ "valid": false
+ },
+ {
+ "description": "Greek KERAIA not followed by anything",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4",
+ "data": "\u03b1\u0375",
+ "valid": false
+ },
+ {
+ "description": "Greek KERAIA followed by Greek",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4",
+ "data": "\u03b1\u0375\u03b2",
+ "valid": true
+ },
+ {
+ "description": "Hebrew GERESH not preceded by Hebrew",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5",
+ "data": "A\u05f3\u05d1",
+ "valid": false
+ },
+ {
+ "description": "Hebrew GERESH not preceded by anything",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5",
+ "data": "\u05f3\u05d1",
+ "valid": false
+ },
+ {
+ "description": "Hebrew GERESH preceded by Hebrew",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5",
+ "data": "\u05d0\u05f3\u05d1",
+ "valid": true
+ },
+ {
+ "description": "Hebrew GERSHAYIM not preceded by Hebrew",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6",
+ "data": "A\u05f4\u05d1",
+ "valid": false
+ },
+ {
+ "description": "Hebrew GERSHAYIM not preceded by anything",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6",
+ "data": "\u05f4\u05d1",
+ "valid": false
+ },
+ {
+ "description": "Hebrew GERSHAYIM preceded by Hebrew",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6",
+ "data": "\u05d0\u05f4\u05d1",
+ "valid": true
+ },
+ {
+ "description": "KATAKANA MIDDLE DOT with no Hiragana, Katakana, or Han",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
+ "data": "def\u30fbabc",
+ "valid": false
+ },
+ {
+ "description": "KATAKANA MIDDLE DOT with no other characters",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
+ "data": "\u30fb",
+ "valid": false
+ },
+ {
+ "description": "KATAKANA MIDDLE DOT with Hiragana",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
+ "data": "\u30fb\u3041",
+ "valid": true
+ },
+ {
+ "description": "KATAKANA MIDDLE DOT with Katakana",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
+ "data": "\u30fb\u30a1",
+ "valid": true
+ },
+ {
+ "description": "KATAKANA MIDDLE DOT with Han",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7",
+ "data": "\u30fb\u4e08",
+ "valid": true
+ },
+ {
+ "description": "Arabic-Indic digits mixed with Extended Arabic-Indic digits",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8",
+ "data": "\u0660\u06f0",
+ "valid": false
+ },
+ {
+ "description": "Arabic-Indic digits not mixed with Extended Arabic-Indic digits",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8",
+ "data": "\u0628\u0660\u0628",
+ "valid": true
+ },
+ {
+ "description": "Extended Arabic-Indic digits not mixed with Arabic-Indic digits",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.9",
+ "data": "\u06f00",
+ "valid": true
+ },
+ {
+ "description": "ZERO WIDTH JOINER not preceded by Virama",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf",
+ "data": "\u0915\u200d\u0937",
+ "valid": false
+ },
+ {
+ "description": "ZERO WIDTH JOINER not preceded by anything",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf",
+ "data": "\u200d\u0937",
+ "valid": false
+ },
+ {
+ "description": "ZERO WIDTH JOINER preceded by Virama",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf",
+ "data": "\u0915\u094d\u200d\u0937",
+ "valid": true
+ },
+ {
+ "description": "ZERO WIDTH NON-JOINER preceded by Virama",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1",
+ "data": "\u0915\u094d\u200c\u0937",
+ "valid": true
+ },
+ {
+ "description": "ZERO WIDTH NON-JOINER not preceded by Virama but matches regexp",
+ "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1 https://www.w3.org/TR/alreq/#h_disjoining_enforcement",
+ "data": "\u0628\u064a\u200c\u0628\u064a",
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/ipv4.json b/tests/draft7/optional/format/ipv4.json
new file mode 100644
index 0000000..4706581
--- /dev/null
+++ b/tests/draft7/optional/format/ipv4.json
@@ -0,0 +1,84 @@
+[
+ {
+ "description": "validation of IP addresses",
+ "schema": { "format": "ipv4" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid IP address",
+ "data": "192.168.0.1",
+ "valid": true
+ },
+ {
+ "description": "an IP address with too many components",
+ "data": "127.0.0.0.1",
+ "valid": false
+ },
+ {
+ "description": "an IP address with out-of-range values",
+ "data": "256.256.256.256",
+ "valid": false
+ },
+ {
+ "description": "an IP address without 4 components",
+ "data": "127.0",
+ "valid": false
+ },
+ {
+ "description": "an IP address as an integer",
+ "data": "0x7f000001",
+ "valid": false
+ },
+ {
+ "description": "an IP address as an integer (decimal)",
+ "data": "2130706433",
+ "valid": false
+ },
+ {
+ "description": "invalid leading zeroes, as they are treated as octals",
+ "comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/",
+ "data": "087.10.0.1",
+ "valid": false
+ },
+ {
+ "description": "value without leading zero is valid",
+ "data": "87.10.0.1",
+ "valid": true
+ },
+ {
+ "description": "invalid non-ASCII '২' (a Bengali 2)",
+ "data": "1২7.0.0.1",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/ipv6.json b/tests/draft7/optional/format/ipv6.json
new file mode 100644
index 0000000..94368f2
--- /dev/null
+++ b/tests/draft7/optional/format/ipv6.json
@@ -0,0 +1,208 @@
+[
+ {
+ "description": "validation of IPv6 addresses",
+ "schema": { "format": "ipv6" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid IPv6 address",
+ "data": "::1",
+ "valid": true
+ },
+ {
+ "description": "an IPv6 address with out-of-range values",
+ "data": "12345::",
+ "valid": false
+ },
+ {
+ "description": "trailing 4 hex symbols is valid",
+ "data": "::abef",
+ "valid": true
+ },
+ {
+ "description": "trailing 5 hex symbols is invalid",
+ "data": "::abcef",
+ "valid": false
+ },
+ {
+ "description": "an IPv6 address with too many components",
+ "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1",
+ "valid": false
+ },
+ {
+ "description": "an IPv6 address containing illegal characters",
+ "data": "::laptop",
+ "valid": false
+ },
+ {
+ "description": "no digits is valid",
+ "data": "::",
+ "valid": true
+ },
+ {
+ "description": "leading colons is valid",
+ "data": "::42:ff:1",
+ "valid": true
+ },
+ {
+ "description": "trailing colons is valid",
+ "data": "d6::",
+ "valid": true
+ },
+ {
+ "description": "missing leading octet is invalid",
+ "data": ":2:3:4:5:6:7:8",
+ "valid": false
+ },
+ {
+ "description": "missing trailing octet is invalid",
+ "data": "1:2:3:4:5:6:7:",
+ "valid": false
+ },
+ {
+ "description": "missing leading octet with omitted octets later",
+ "data": ":2:3:4::8",
+ "valid": false
+ },
+ {
+ "description": "single set of double colons in the middle is valid",
+ "data": "1:d6::42",
+ "valid": true
+ },
+ {
+ "description": "two sets of double colons is invalid",
+ "data": "1::d6::42",
+ "valid": false
+ },
+ {
+ "description": "mixed format with the ipv4 section as decimal octets",
+ "data": "1::d6:192.168.0.1",
+ "valid": true
+ },
+ {
+ "description": "mixed format with double colons between the sections",
+ "data": "1:2::192.168.0.1",
+ "valid": true
+ },
+ {
+ "description": "mixed format with ipv4 section with octet out of range",
+ "data": "1::2:192.168.256.1",
+ "valid": false
+ },
+ {
+ "description": "mixed format with ipv4 section with a hex octet",
+ "data": "1::2:192.168.ff.1",
+ "valid": false
+ },
+ {
+ "description": "mixed format with leading double colons (ipv4-mapped ipv6 address)",
+ "data": "::ffff:192.168.0.1",
+ "valid": true
+ },
+ {
+ "description": "triple colons is invalid",
+ "data": "1:2:3:4:5:::8",
+ "valid": false
+ },
+ {
+ "description": "8 octets",
+ "data": "1:2:3:4:5:6:7:8",
+ "valid": true
+ },
+ {
+ "description": "insufficient octets without double colons",
+ "data": "1:2:3:4:5:6:7",
+ "valid": false
+ },
+ {
+ "description": "no colons is invalid",
+ "data": "1",
+ "valid": false
+ },
+ {
+ "description": "ipv4 is not ipv6",
+ "data": "127.0.0.1",
+ "valid": false
+ },
+ {
+ "description": "ipv4 segment must have 4 octets",
+ "data": "1:2:3:4:1.2.3",
+ "valid": false
+ },
+ {
+ "description": "leading whitespace is invalid",
+ "data": " ::1",
+ "valid": false
+ },
+ {
+ "description": "trailing whitespace is invalid",
+ "data": "::1 ",
+ "valid": false
+ },
+ {
+ "description": "netmask is not a part of ipv6 address",
+ "data": "fe80::/64",
+ "valid": false
+ },
+ {
+ "description": "zone id is not a part of ipv6 address",
+ "data": "fe80::a%eth1",
+ "valid": false
+ },
+ {
+ "description": "a long valid ipv6",
+ "data": "1000:1000:1000:1000:1000:1000:255.255.255.255",
+ "valid": true
+ },
+ {
+ "description": "a long invalid ipv6, below length limit, first",
+ "data": "100:100:100:100:100:100:255.255.255.255.255",
+ "valid": false
+ },
+ {
+ "description": "a long invalid ipv6, below length limit, second",
+ "data": "100:100:100:100:100:100:100:255.255.255.255",
+ "valid": false
+ },
+ {
+ "description": "invalid non-ASCII '৪' (a Bengali 4)",
+ "data": "1:2:3:4:5:6:7:৪",
+ "valid": false
+ },
+ {
+ "description": "invalid non-ASCII '৪' (a Bengali 4) in the IPv4 portion",
+ "data": "1:2::192.16৪.0.1",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/iri-reference.json b/tests/draft7/optional/format/iri-reference.json
new file mode 100644
index 0000000..c6b4c22
--- /dev/null
+++ b/tests/draft7/optional/format/iri-reference.json
@@ -0,0 +1,73 @@
+[
+ {
+ "description": "validation of IRI References",
+ "schema": { "format": "iri-reference" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid IRI",
+ "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx",
+ "valid": true
+ },
+ {
+ "description": "a valid protocol-relative IRI Reference",
+ "data": "//ƒøø.ßår/?∂éœ=πîx#πîüx",
+ "valid": true
+ },
+ {
+ "description": "a valid relative IRI Reference",
+ "data": "/âππ",
+ "valid": true
+ },
+ {
+ "description": "an invalid IRI Reference",
+ "data": "\\\\WINDOWS\\filëßåré",
+ "valid": false
+ },
+ {
+ "description": "a valid IRI Reference",
+ "data": "âππ",
+ "valid": true
+ },
+ {
+ "description": "a valid IRI fragment",
+ "data": "#ƒrägmênt",
+ "valid": true
+ },
+ {
+ "description": "an invalid IRI fragment",
+ "data": "#ƒräg\\mênt",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/iri.json b/tests/draft7/optional/format/iri.json
new file mode 100644
index 0000000..a0d12ae
--- /dev/null
+++ b/tests/draft7/optional/format/iri.json
@@ -0,0 +1,83 @@
+[
+ {
+ "description": "validation of IRIs",
+ "schema": { "format": "iri" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid IRI with anchor tag",
+ "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx",
+ "valid": true
+ },
+ {
+ "description": "a valid IRI with anchor tag and parentheses",
+ "data": "http://ƒøø.com/blah_(wîkïpédiå)_blah#ßité-1",
+ "valid": true
+ },
+ {
+ "description": "a valid IRI with URL-encoded stuff",
+ "data": "http://ƒøø.ßår/?q=Test%20URL-encoded%20stuff",
+ "valid": true
+ },
+ {
+ "description": "a valid IRI with many special characters",
+ "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com",
+ "valid": true
+ },
+ {
+ "description": "a valid IRI based on IPv6",
+ "data": "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]",
+ "valid": true
+ },
+ {
+ "description": "an invalid IRI based on IPv6",
+ "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334",
+ "valid": false
+ },
+ {
+ "description": "an invalid relative IRI Reference",
+ "data": "/abc",
+ "valid": false
+ },
+ {
+ "description": "an invalid IRI",
+ "data": "\\\\WINDOWS\\filëßåré",
+ "valid": false
+ },
+ {
+ "description": "an invalid IRI though valid IRI reference",
+ "data": "âππ",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/json-pointer.json b/tests/draft7/optional/format/json-pointer.json
new file mode 100644
index 0000000..a0346b5
--- /dev/null
+++ b/tests/draft7/optional/format/json-pointer.json
@@ -0,0 +1,198 @@
+[
+ {
+ "description": "validation of JSON-pointers (JSON String Representation)",
+ "schema": { "format": "json-pointer" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid JSON-pointer",
+ "data": "/foo/bar~0/baz~1/%a",
+ "valid": true
+ },
+ {
+ "description": "not a valid JSON-pointer (~ not escaped)",
+ "data": "/foo/bar~",
+ "valid": false
+ },
+ {
+ "description": "valid JSON-pointer with empty segment",
+ "data": "/foo//bar",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer with the last empty segment",
+ "data": "/foo/bar/",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #1",
+ "data": "",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #2",
+ "data": "/foo",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #3",
+ "data": "/foo/0",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #4",
+ "data": "/",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #5",
+ "data": "/a~1b",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #6",
+ "data": "/c%d",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #7",
+ "data": "/e^f",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #8",
+ "data": "/g|h",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #9",
+ "data": "/i\\j",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #10",
+ "data": "/k\"l",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #11",
+ "data": "/ ",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer as stated in RFC 6901 #12",
+ "data": "/m~0n",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer used adding to the last array position",
+ "data": "/foo/-",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer (- used as object member name)",
+ "data": "/foo/-/bar",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer (multiple escaped characters)",
+ "data": "/~1~0~0~1~1",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer (escaped with fraction part) #1",
+ "data": "/~1.1",
+ "valid": true
+ },
+ {
+ "description": "valid JSON-pointer (escaped with fraction part) #2",
+ "data": "/~0.1",
+ "valid": true
+ },
+ {
+ "description": "not a valid JSON-pointer (URI Fragment Identifier) #1",
+ "data": "#",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (URI Fragment Identifier) #2",
+ "data": "#/",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (URI Fragment Identifier) #3",
+ "data": "#a",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (some escaped, but not all) #1",
+ "data": "/~0~",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (some escaped, but not all) #2",
+ "data": "/~0/~",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (wrong escape character) #1",
+ "data": "/~2",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (wrong escape character) #2",
+ "data": "/~-1",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (multiple characters not escaped)",
+ "data": "/~~",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1",
+ "data": "a",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2",
+ "data": "0",
+ "valid": false
+ },
+ {
+ "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3",
+ "data": "a/a",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/regex.json b/tests/draft7/optional/format/regex.json
new file mode 100644
index 0000000..3449177
--- /dev/null
+++ b/tests/draft7/optional/format/regex.json
@@ -0,0 +1,48 @@
+[
+ {
+ "description": "validation of regular expressions",
+ "schema": { "format": "regex" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid regular expression",
+ "data": "([abc])+\\s+$",
+ "valid": true
+ },
+ {
+ "description": "a regular expression with unclosed parens is invalid",
+ "data": "^(abc]",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/relative-json-pointer.json b/tests/draft7/optional/format/relative-json-pointer.json
new file mode 100644
index 0000000..e50e505
--- /dev/null
+++ b/tests/draft7/optional/format/relative-json-pointer.json
@@ -0,0 +1,98 @@
+[
+ {
+ "description": "validation of Relative JSON Pointers (RJP)",
+ "schema": { "format": "relative-json-pointer" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid upwards RJP",
+ "data": "1",
+ "valid": true
+ },
+ {
+ "description": "a valid downwards RJP",
+ "data": "0/foo/bar",
+ "valid": true
+ },
+ {
+ "description": "a valid up and then down RJP, with array index",
+ "data": "2/0/baz/1/zip",
+ "valid": true
+ },
+ {
+ "description": "a valid RJP taking the member or index name",
+ "data": "0#",
+ "valid": true
+ },
+ {
+ "description": "an invalid RJP that is a valid JSON Pointer",
+ "data": "/foo/bar",
+ "valid": false
+ },
+ {
+ "description": "negative prefix",
+ "data": "-1/foo/bar",
+ "valid": false
+ },
+ {
+ "description": "explicit positive prefix",
+ "data": "+1/foo/bar",
+ "valid": false
+ },
+ {
+ "description": "## is not a valid json-pointer",
+ "data": "0##",
+ "valid": false
+ },
+ {
+ "description": "zero cannot be followed by other digits, plus json-pointer",
+ "data": "01/a",
+ "valid": false
+ },
+ {
+ "description": "zero cannot be followed by other digits, plus octothorpe",
+ "data": "01#",
+ "valid": false
+ },
+ {
+ "description": "empty string",
+ "data": "",
+ "valid": false
+ },
+ {
+ "description": "multi-digit integer prefix",
+ "data": "120/foo/bar",
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/time.json b/tests/draft7/optional/format/time.json
new file mode 100644
index 0000000..920db61
--- /dev/null
+++ b/tests/draft7/optional/format/time.json
@@ -0,0 +1,213 @@
+[
+ {
+ "description": "validation of time strings",
+ "schema": { "format": "time" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid time string",
+ "data": "08:30:06Z",
+ "valid": true
+ },
+ {
+ "description": "a valid time string with leap second, Zulu",
+ "data": "23:59:60Z",
+ "valid": true
+ },
+ {
+ "description": "invalid leap second, Zulu (wrong hour)",
+ "data": "22:59:60Z",
+ "valid": false
+ },
+ {
+ "description": "invalid leap second, Zulu (wrong minute)",
+ "data": "23:58:60Z",
+ "valid": false
+ },
+ {
+ "description": "valid leap second, zero time-offset",
+ "data": "23:59:60+00:00",
+ "valid": true
+ },
+ {
+ "description": "invalid leap second, zero time-offset (wrong hour)",
+ "data": "22:59:60+00:00",
+ "valid": false
+ },
+ {
+ "description": "invalid leap second, zero time-offset (wrong minute)",
+ "data": "23:58:60+00:00",
+ "valid": false
+ },
+ {
+ "description": "valid leap second, positive time-offset",
+ "data": "01:29:60+01:30",
+ "valid": true
+ },
+ {
+ "description": "valid leap second, large positive time-offset",
+ "data": "23:29:60+23:30",
+ "valid": true
+ },
+ {
+ "description": "invalid leap second, positive time-offset (wrong hour)",
+ "data": "23:59:60+01:00",
+ "valid": false
+ },
+ {
+ "description": "invalid leap second, positive time-offset (wrong minute)",
+ "data": "23:59:60+00:30",
+ "valid": false
+ },
+ {
+ "description": "valid leap second, negative time-offset",
+ "data": "15:59:60-08:00",
+ "valid": true
+ },
+ {
+ "description": "valid leap second, large negative time-offset",
+ "data": "00:29:60-23:30",
+ "valid": true
+ },
+ {
+ "description": "invalid leap second, negative time-offset (wrong hour)",
+ "data": "23:59:60-01:00",
+ "valid": false
+ },
+ {
+ "description": "invalid leap second, negative time-offset (wrong minute)",
+ "data": "23:59:60-00:30",
+ "valid": false
+ },
+ {
+ "description": "a valid time string with second fraction",
+ "data": "23:20:50.52Z",
+ "valid": true
+ },
+ {
+ "description": "a valid time string with precise second fraction",
+ "data": "08:30:06.283185Z",
+ "valid": true
+ },
+ {
+ "description": "a valid time string with plus offset",
+ "data": "08:30:06+00:20",
+ "valid": true
+ },
+ {
+ "description": "a valid time string with minus offset",
+ "data": "08:30:06-08:00",
+ "valid": true
+ },
+ {
+ "description": "a valid time string with case-insensitive Z",
+ "data": "08:30:06z",
+ "valid": true
+ },
+ {
+ "description": "an invalid time string with invalid hour",
+ "data": "24:00:00Z",
+ "valid": false
+ },
+ {
+ "description": "an invalid time string with invalid minute",
+ "data": "00:60:00Z",
+ "valid": false
+ },
+ {
+ "description": "an invalid time string with invalid second",
+ "data": "00:00:61Z",
+ "valid": false
+ },
+ {
+ "description": "an invalid time string with invalid leap second (wrong hour)",
+ "data": "22:59:60Z",
+ "valid": false
+ },
+ {
+ "description": "an invalid time string with invalid leap second (wrong minute)",
+ "data": "23:58:60Z",
+ "valid": false
+ },
+ {
+ "description": "an invalid time string with invalid time numoffset hour",
+ "data": "01:02:03+24:00",
+ "valid": false
+ },
+ {
+ "description": "an invalid time string with invalid time numoffset minute",
+ "data": "01:02:03+00:60",
+ "valid": false
+ },
+ {
+ "description": "an invalid time string with invalid time with both Z and numoffset",
+ "data": "01:02:03Z+00:30",
+ "valid": false
+ },
+ {
+ "description": "an invalid offset indicator",
+ "data": "08:30:06 PST",
+ "valid": false
+ },
+ {
+ "description": "only RFC3339 not all of ISO 8601 are valid",
+ "data": "01:01:01,1111",
+ "valid": false
+ },
+ {
+ "description": "no time offset",
+ "data": "12:00:00",
+ "valid": false
+ },
+ {
+ "description": "no time offset with second fraction",
+ "data": "12:00:00.52",
+ "valid": false
+ },
+ {
+ "description": "invalid non-ASCII '২' (a Bengali 2)",
+ "data": "1২:00:00Z",
+ "valid": false
+ },
+ {
+ "description": "offset not starting with plus or minus",
+ "data": "08:30:06#00:20",
+ "valid": false
+ },
+ {
+ "description": "contains letters",
+ "data": "ab:cd:ef",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/unknown.json b/tests/draft7/optional/format/unknown.json
new file mode 100644
index 0000000..12339ae
--- /dev/null
+++ b/tests/draft7/optional/format/unknown.json
@@ -0,0 +1,43 @@
+[
+ {
+ "description": "unknown format",
+ "schema": { "format": "unknown" },
+ "tests": [
+ {
+ "description": "unknown formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "unknown formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "unknown formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "unknown formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "unknown formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "unknown formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "unknown formats ignore strings",
+ "data": "string",
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/uri-reference.json b/tests/draft7/optional/format/uri-reference.json
new file mode 100644
index 0000000..7cdf228
--- /dev/null
+++ b/tests/draft7/optional/format/uri-reference.json
@@ -0,0 +1,73 @@
+[
+ {
+ "description": "validation of URI References",
+ "schema": { "format": "uri-reference" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid URI",
+ "data": "http://foo.bar/?baz=qux#quux",
+ "valid": true
+ },
+ {
+ "description": "a valid protocol-relative URI Reference",
+ "data": "//foo.bar/?baz=qux#quux",
+ "valid": true
+ },
+ {
+ "description": "a valid relative URI Reference",
+ "data": "/abc",
+ "valid": true
+ },
+ {
+ "description": "an invalid URI Reference",
+ "data": "\\\\WINDOWS\\fileshare",
+ "valid": false
+ },
+ {
+ "description": "a valid URI Reference",
+ "data": "abc",
+ "valid": true
+ },
+ {
+ "description": "a valid URI fragment",
+ "data": "#fragment",
+ "valid": true
+ },
+ {
+ "description": "an invalid URI fragment",
+ "data": "#frag\\ment",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/uri-template.json b/tests/draft7/optional/format/uri-template.json
new file mode 100644
index 0000000..df355c5
--- /dev/null
+++ b/tests/draft7/optional/format/uri-template.json
@@ -0,0 +1,58 @@
+[
+ {
+ "description": "format: uri-template",
+ "schema": { "format": "uri-template" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid uri-template",
+ "data": "http://example.com/dictionary/{term:1}/{term}",
+ "valid": true
+ },
+ {
+ "description": "an invalid uri-template",
+ "data": "http://example.com/dictionary/{term:1}/{term",
+ "valid": false
+ },
+ {
+ "description": "a valid uri-template without variables",
+ "data": "http://example.com/dictionary",
+ "valid": true
+ },
+ {
+ "description": "a valid relative uri-template",
+ "data": "dictionary/{term:1}/{term}",
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/format/uri.json b/tests/draft7/optional/format/uri.json
new file mode 100644
index 0000000..4b48d40
--- /dev/null
+++ b/tests/draft7/optional/format/uri.json
@@ -0,0 +1,138 @@
+[
+ {
+ "description": "validation of URIs",
+ "schema": { "format": "uri" },
+ "tests": [
+ {
+ "description": "all string formats ignore integers",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore floats",
+ "data": 13.7,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore booleans",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "all string formats ignore nulls",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "a valid URL with anchor tag",
+ "data": "http://foo.bar/?baz=qux#quux",
+ "valid": true
+ },
+ {
+ "description": "a valid URL with anchor tag and parentheses",
+ "data": "http://foo.com/blah_(wikipedia)_blah#cite-1",
+ "valid": true
+ },
+ {
+ "description": "a valid URL with URL-encoded stuff",
+ "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff",
+ "valid": true
+ },
+ {
+ "description": "a valid puny-coded URL ",
+ "data": "http://xn--nw2a.xn--j6w193g/",
+ "valid": true
+ },
+ {
+ "description": "a valid URL with many special characters",
+ "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com",
+ "valid": true
+ },
+ {
+ "description": "a valid URL based on IPv4",
+ "data": "http://223.255.255.254",
+ "valid": true
+ },
+ {
+ "description": "a valid URL with ftp scheme",
+ "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt",
+ "valid": true
+ },
+ {
+ "description": "a valid URL for a simple text file",
+ "data": "http://www.ietf.org/rfc/rfc2396.txt",
+ "valid": true
+ },
+ {
+ "description": "a valid URL ",
+ "data": "ldap://[2001:db8::7]/c=GB?objectClass?one",
+ "valid": true
+ },
+ {
+ "description": "a valid mailto URI",
+ "data": "mailto:John.Doe@example.com",
+ "valid": true
+ },
+ {
+ "description": "a valid newsgroup URI",
+ "data": "news:comp.infosystems.www.servers.unix",
+ "valid": true
+ },
+ {
+ "description": "a valid tel URI",
+ "data": "tel:+1-816-555-1212",
+ "valid": true
+ },
+ {
+ "description": "a valid URN",
+ "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2",
+ "valid": true
+ },
+ {
+ "description": "an invalid protocol-relative URI Reference",
+ "data": "//foo.bar/?baz=qux#quux",
+ "valid": false
+ },
+ {
+ "description": "an invalid relative URI Reference",
+ "data": "/abc",
+ "valid": false
+ },
+ {
+ "description": "an invalid URI",
+ "data": "\\\\WINDOWS\\fileshare",
+ "valid": false
+ },
+ {
+ "description": "an invalid URI though valid URI reference",
+ "data": "abc",
+ "valid": false
+ },
+ {
+ "description": "an invalid URI with spaces",
+ "data": "http:// shouldfail.com",
+ "valid": false
+ },
+ {
+ "description": "an invalid URI with spaces and missing scheme",
+ "data": ":// should fail",
+ "valid": false
+ },
+ {
+ "description": "an invalid URI with comma in scheme",
+ "data": "bar,baz:foo",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/optional/non-bmp-regex.json b/tests/draft7/optional/non-bmp-regex.json
new file mode 100644
index 0000000..dd67af2
--- /dev/null
+++ b/tests/draft7/optional/non-bmp-regex.json
@@ -0,0 +1,82 @@
+[
+ {
+ "description": "Proper UTF-16 surrogate pair handling: pattern",
+ "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters",
+ "schema": { "pattern": "^🐲*$" },
+ "tests": [
+ {
+ "description": "matches empty",
+ "data": "",
+ "valid": true
+ },
+ {
+ "description": "matches single",
+ "data": "🐲",
+ "valid": true
+ },
+ {
+ "description": "matches two",
+ "data": "🐲🐲",
+ "valid": true
+ },
+ {
+ "description": "doesn't match one",
+ "data": "🐉",
+ "valid": false
+ },
+ {
+ "description": "doesn't match two",
+ "data": "🐉🐉",
+ "valid": false
+ },
+ {
+ "description": "doesn't match one ASCII",
+ "data": "D",
+ "valid": false
+ },
+ {
+ "description": "doesn't match two ASCII",
+ "data": "DD",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "Proper UTF-16 surrogate pair handling: patternProperties",
+ "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters",
+ "schema": {
+ "patternProperties": {
+ "^🐲*$": {
+ "type": "integer"
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "matches empty",
+ "data": { "": 1 },
+ "valid": true
+ },
+ {
+ "description": "matches single",
+ "data": { "🐲": 1 },
+ "valid": true
+ },
+ {
+ "description": "matches two",
+ "data": { "🐲🐲": 1 },
+ "valid": true
+ },
+ {
+ "description": "doesn't match one",
+ "data": { "🐲": "hello" },
+ "valid": false
+ },
+ {
+ "description": "doesn't match two",
+ "data": { "🐲🐲": "hello" },
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/pattern.json b/tests/draft7/pattern.json
new file mode 100644
index 0000000..92db0f9
--- /dev/null
+++ b/tests/draft7/pattern.json
@@ -0,0 +1,59 @@
+[
+ {
+ "description": "pattern validation",
+ "schema": {"pattern": "^a*$"},
+ "tests": [
+ {
+ "description": "a matching pattern is valid",
+ "data": "aaa",
+ "valid": true
+ },
+ {
+ "description": "a non-matching pattern is invalid",
+ "data": "abc",
+ "valid": false
+ },
+ {
+ "description": "ignores booleans",
+ "data": true,
+ "valid": true
+ },
+ {
+ "description": "ignores integers",
+ "data": 123,
+ "valid": true
+ },
+ {
+ "description": "ignores floats",
+ "data": 1.0,
+ "valid": true
+ },
+ {
+ "description": "ignores objects",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "ignores arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "ignores null",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "pattern is not anchored",
+ "schema": {"pattern": "a+"},
+ "tests": [
+ {
+ "description": "matches a substring",
+ "data": "xxaayy",
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/patternProperties.json b/tests/draft7/patternProperties.json
new file mode 100644
index 0000000..c276e64
--- /dev/null
+++ b/tests/draft7/patternProperties.json
@@ -0,0 +1,171 @@
+[
+ {
+ "description":
+ "patternProperties validates properties matching a regex",
+ "schema": {
+ "patternProperties": {
+ "f.*o": {"type": "integer"}
+ }
+ },
+ "tests": [
+ {
+ "description": "a single valid match is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "multiple valid matches is valid",
+ "data": {"foo": 1, "foooooo" : 2},
+ "valid": true
+ },
+ {
+ "description": "a single invalid match is invalid",
+ "data": {"foo": "bar", "fooooo": 2},
+ "valid": false
+ },
+ {
+ "description": "multiple invalid matches is invalid",
+ "data": {"foo": "bar", "foooooo" : "baz"},
+ "valid": false
+ },
+ {
+ "description": "ignores arrays",
+ "data": ["foo"],
+ "valid": true
+ },
+ {
+ "description": "ignores strings",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "multiple simultaneous patternProperties are validated",
+ "schema": {
+ "patternProperties": {
+ "a*": {"type": "integer"},
+ "aaa*": {"maximum": 20}
+ }
+ },
+ "tests": [
+ {
+ "description": "a single valid match is valid",
+ "data": {"a": 21},
+ "valid": true
+ },
+ {
+ "description": "a simultaneous match is valid",
+ "data": {"aaaa": 18},
+ "valid": true
+ },
+ {
+ "description": "multiple matches is valid",
+ "data": {"a": 21, "aaaa": 18},
+ "valid": true
+ },
+ {
+ "description": "an invalid due to one is invalid",
+ "data": {"a": "bar"},
+ "valid": false
+ },
+ {
+ "description": "an invalid due to the other is invalid",
+ "data": {"aaaa": 31},
+ "valid": false
+ },
+ {
+ "description": "an invalid due to both is invalid",
+ "data": {"aaa": "foo", "aaaa": 31},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "regexes are not anchored by default and are case sensitive",
+ "schema": {
+ "patternProperties": {
+ "[0-9]{2,}": { "type": "boolean" },
+ "X_": { "type": "string" }
+ }
+ },
+ "tests": [
+ {
+ "description": "non recognized members are ignored",
+ "data": { "answer 1": "42" },
+ "valid": true
+ },
+ {
+ "description": "recognized members are accounted for",
+ "data": { "a31b": null },
+ "valid": false
+ },
+ {
+ "description": "regexes are case sensitive",
+ "data": { "a_x_3": 3 },
+ "valid": true
+ },
+ {
+ "description": "regexes are case sensitive, 2",
+ "data": { "a_X_3": 3 },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "patternProperties with boolean schemas",
+ "schema": {
+ "patternProperties": {
+ "f.*": true,
+ "b.*": false
+ }
+ },
+ "tests": [
+ {
+ "description": "object with property matching schema true is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "object with property matching schema false is invalid",
+ "data": {"bar": 2},
+ "valid": false
+ },
+ {
+ "description": "object with both properties is invalid",
+ "data": {"foo": 1, "bar": 2},
+ "valid": false
+ },
+ {
+ "description": "object with a property matching both true and false is invalid",
+ "data": {"foobar":1},
+ "valid": false
+ },
+ {
+ "description": "empty object is valid",
+ "data": {},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "patternProperties with null valued instance properties",
+ "schema": {
+ "patternProperties": {
+ "^.*bar$": {"type": "null"}
+ }
+ },
+ "tests": [
+ {
+ "description": "allows null values",
+ "data": {"foobar": null},
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/properties.json b/tests/draft7/properties.json
new file mode 100644
index 0000000..5b971ca
--- /dev/null
+++ b/tests/draft7/properties.json
@@ -0,0 +1,236 @@
+[
+ {
+ "description": "object properties validation",
+ "schema": {
+ "properties": {
+ "foo": {"type": "integer"},
+ "bar": {"type": "string"}
+ }
+ },
+ "tests": [
+ {
+ "description": "both properties present and valid is valid",
+ "data": {"foo": 1, "bar": "baz"},
+ "valid": true
+ },
+ {
+ "description": "one property invalid is invalid",
+ "data": {"foo": 1, "bar": {}},
+ "valid": false
+ },
+ {
+ "description": "both properties invalid is invalid",
+ "data": {"foo": [], "bar": {}},
+ "valid": false
+ },
+ {
+ "description": "doesn't invalidate other properties",
+ "data": {"quux": []},
+ "valid": true
+ },
+ {
+ "description": "ignores arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description":
+ "properties, patternProperties, additionalProperties interaction",
+ "schema": {
+ "properties": {
+ "foo": {"type": "array", "maxItems": 3},
+ "bar": {"type": "array"}
+ },
+ "patternProperties": {"f.o": {"minItems": 2}},
+ "additionalProperties": {"type": "integer"}
+ },
+ "tests": [
+ {
+ "description": "property validates property",
+ "data": {"foo": [1, 2]},
+ "valid": true
+ },
+ {
+ "description": "property invalidates property",
+ "data": {"foo": [1, 2, 3, 4]},
+ "valid": false
+ },
+ {
+ "description": "patternProperty invalidates property",
+ "data": {"foo": []},
+ "valid": false
+ },
+ {
+ "description": "patternProperty validates nonproperty",
+ "data": {"fxo": [1, 2]},
+ "valid": true
+ },
+ {
+ "description": "patternProperty invalidates nonproperty",
+ "data": {"fxo": []},
+ "valid": false
+ },
+ {
+ "description": "additionalProperty ignores property",
+ "data": {"bar": []},
+ "valid": true
+ },
+ {
+ "description": "additionalProperty validates others",
+ "data": {"quux": 3},
+ "valid": true
+ },
+ {
+ "description": "additionalProperty invalidates others",
+ "data": {"quux": "foo"},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "properties with boolean schema",
+ "schema": {
+ "properties": {
+ "foo": true,
+ "bar": false
+ }
+ },
+ "tests": [
+ {
+ "description": "no property present is valid",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "only 'true' property present is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "only 'false' property present is invalid",
+ "data": {"bar": 2},
+ "valid": false
+ },
+ {
+ "description": "both properties present is invalid",
+ "data": {"foo": 1, "bar": 2},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "properties with escaped characters",
+ "schema": {
+ "properties": {
+ "foo\nbar": {"type": "number"},
+ "foo\"bar": {"type": "number"},
+ "foo\\bar": {"type": "number"},
+ "foo\rbar": {"type": "number"},
+ "foo\tbar": {"type": "number"},
+ "foo\fbar": {"type": "number"}
+ }
+ },
+ "tests": [
+ {
+ "description": "object with all numbers is valid",
+ "data": {
+ "foo\nbar": 1,
+ "foo\"bar": 1,
+ "foo\\bar": 1,
+ "foo\rbar": 1,
+ "foo\tbar": 1,
+ "foo\fbar": 1
+ },
+ "valid": true
+ },
+ {
+ "description": "object with strings is invalid",
+ "data": {
+ "foo\nbar": "1",
+ "foo\"bar": "1",
+ "foo\\bar": "1",
+ "foo\rbar": "1",
+ "foo\tbar": "1",
+ "foo\fbar": "1"
+ },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "properties with null valued instance properties",
+ "schema": {
+ "properties": {
+ "foo": {"type": "null"}
+ }
+ },
+ "tests": [
+ {
+ "description": "allows null values",
+ "data": {"foo": null},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "properties whose names are Javascript object property names",
+ "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
+ "schema": {
+ "properties": {
+ "__proto__": {"type": "number"},
+ "toString": {
+ "properties": { "length": { "type": "string" } }
+ },
+ "constructor": {"type": "number"}
+ }
+ },
+ "tests": [
+ {
+ "description": "ignores arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "none of the properties mentioned",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "__proto__ not valid",
+ "data": { "__proto__": "foo" },
+ "valid": false
+ },
+ {
+ "description": "toString not valid",
+ "data": { "toString": { "length": 37 } },
+ "valid": false
+ },
+ {
+ "description": "constructor not valid",
+ "data": { "constructor": { "length": 37 } },
+ "valid": false
+ },
+ {
+ "description": "all present and valid",
+ "data": {
+ "__proto__": 12,
+ "toString": { "length": "foo" },
+ "constructor": 37
+ },
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/propertyNames.json b/tests/draft7/propertyNames.json
new file mode 100644
index 0000000..f0788e6
--- /dev/null
+++ b/tests/draft7/propertyNames.json
@@ -0,0 +1,107 @@
+[
+ {
+ "description": "propertyNames validation",
+ "schema": {
+ "propertyNames": {"maxLength": 3}
+ },
+ "tests": [
+ {
+ "description": "all property names valid",
+ "data": {
+ "f": {},
+ "foo": {}
+ },
+ "valid": true
+ },
+ {
+ "description": "some property names invalid",
+ "data": {
+ "foo": {},
+ "foobar": {}
+ },
+ "valid": false
+ },
+ {
+ "description": "object without properties is valid",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "ignores arrays",
+ "data": [1, 2, 3, 4],
+ "valid": true
+ },
+ {
+ "description": "ignores strings",
+ "data": "foobar",
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "propertyNames validation with pattern",
+ "schema": {
+ "propertyNames": { "pattern": "^a+$" }
+ },
+ "tests": [
+ {
+ "description": "matching property names valid",
+ "data": {
+ "a": {},
+ "aa": {},
+ "aaa": {}
+ },
+ "valid": true
+ },
+ {
+ "description": "non-matching property name is invalid",
+ "data": {
+ "aaA": {}
+ },
+ "valid": false
+ },
+ {
+ "description": "object without properties is valid",
+ "data": {},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "propertyNames with boolean schema true",
+ "schema": {"propertyNames": true},
+ "tests": [
+ {
+ "description": "object with any properties is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "empty object is valid",
+ "data": {},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "propertyNames with boolean schema false",
+ "schema": {"propertyNames": false},
+ "tests": [
+ {
+ "description": "object with any properties is invalid",
+ "data": {"foo": 1},
+ "valid": false
+ },
+ {
+ "description": "empty object is valid",
+ "data": {},
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/ref.json b/tests/draft7/ref.json
new file mode 100644
index 0000000..c9daf8f
--- /dev/null
+++ b/tests/draft7/ref.json
@@ -0,0 +1,888 @@
+[
+ {
+ "description": "root pointer ref",
+ "schema": {
+ "properties": {
+ "foo": {"$ref": "#"}
+ },
+ "additionalProperties": false
+ },
+ "tests": [
+ {
+ "description": "match",
+ "data": {"foo": false},
+ "valid": true
+ },
+ {
+ "description": "recursive match",
+ "data": {"foo": {"foo": false}},
+ "valid": true
+ },
+ {
+ "description": "mismatch",
+ "data": {"bar": false},
+ "valid": false
+ },
+ {
+ "description": "recursive mismatch",
+ "data": {"foo": {"bar": false}},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "relative pointer ref to object",
+ "schema": {
+ "properties": {
+ "foo": {"type": "integer"},
+ "bar": {"$ref": "#/properties/foo"}
+ }
+ },
+ "tests": [
+ {
+ "description": "match",
+ "data": {"bar": 3},
+ "valid": true
+ },
+ {
+ "description": "mismatch",
+ "data": {"bar": true},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "relative pointer ref to array",
+ "schema": {
+ "items": [
+ {"type": "integer"},
+ {"$ref": "#/items/0"}
+ ]
+ },
+ "tests": [
+ {
+ "description": "match array",
+ "data": [1, 2],
+ "valid": true
+ },
+ {
+ "description": "mismatch array",
+ "data": [1, "foo"],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "escaped pointer ref",
+ "schema": {
+ "definitions": {
+ "tilde~field": {"type": "integer"},
+ "slash/field": {"type": "integer"},
+ "percent%field": {"type": "integer"}
+ },
+ "properties": {
+ "tilde": {"$ref": "#/definitions/tilde~0field"},
+ "slash": {"$ref": "#/definitions/slash~1field"},
+ "percent": {"$ref": "#/definitions/percent%25field"}
+ }
+ },
+ "tests": [
+ {
+ "description": "slash invalid",
+ "data": {"slash": "aoeu"},
+ "valid": false
+ },
+ {
+ "description": "tilde invalid",
+ "data": {"tilde": "aoeu"},
+ "valid": false
+ },
+ {
+ "description": "percent invalid",
+ "data": {"percent": "aoeu"},
+ "valid": false
+ },
+ {
+ "description": "slash valid",
+ "data": {"slash": 123},
+ "valid": true
+ },
+ {
+ "description": "tilde valid",
+ "data": {"tilde": 123},
+ "valid": true
+ },
+ {
+ "description": "percent valid",
+ "data": {"percent": 123},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "nested refs",
+ "schema": {
+ "definitions": {
+ "a": {"type": "integer"},
+ "b": {"$ref": "#/definitions/a"},
+ "c": {"$ref": "#/definitions/b"}
+ },
+ "allOf": [{ "$ref": "#/definitions/c" }]
+ },
+ "tests": [
+ {
+ "description": "nested ref valid",
+ "data": 5,
+ "valid": true
+ },
+ {
+ "description": "nested ref invalid",
+ "data": "a",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "ref overrides any sibling keywords",
+ "schema": {
+ "definitions": {
+ "reffed": {
+ "type": "array"
+ }
+ },
+ "properties": {
+ "foo": {
+ "$ref": "#/definitions/reffed",
+ "maxItems": 2
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "ref valid",
+ "data": { "foo": [] },
+ "valid": true
+ },
+ {
+ "description": "ref valid, maxItems ignored",
+ "data": { "foo": [ 1, 2, 3] },
+ "valid": true
+ },
+ {
+ "description": "ref invalid",
+ "data": { "foo": "string" },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "$ref prevents a sibling $id from changing the base uri",
+ "schema": {
+ "$id": "http://localhost:1234/sibling_id/base/",
+ "definitions": {
+ "foo": {
+ "$id": "http://localhost:1234/sibling_id/foo.json",
+ "type": "string"
+ },
+ "base_foo": {
+ "$comment": "this canonical uri is http://localhost:1234/sibling_id/base/foo.json",
+ "$id": "foo.json",
+ "type": "number"
+ }
+ },
+ "allOf": [
+ {
+ "$comment": "$ref resolves to http://localhost:1234/sibling_id/base/foo.json, not http://localhost:1234/sibling_id/foo.json",
+ "$id": "http://localhost:1234/sibling_id/",
+ "$ref": "foo.json"
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "$ref resolves to /definitions/base_foo, data does not validate",
+ "data": "a",
+ "valid": false
+ },
+ {
+ "description": "$ref resolves to /definitions/base_foo, data validates",
+ "data": 1,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "remote ref, containing refs itself",
+ "schema": {"$ref": "http://json-schema.org/draft-07/schema#"},
+ "tests": [
+ {
+ "description": "remote ref valid",
+ "data": {"minLength": 1},
+ "valid": true
+ },
+ {
+ "description": "remote ref invalid",
+ "data": {"minLength": -1},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "property named $ref that is not a reference",
+ "schema": {
+ "properties": {
+ "$ref": {"type": "string"}
+ }
+ },
+ "tests": [
+ {
+ "description": "property named $ref valid",
+ "data": {"$ref": "a"},
+ "valid": true
+ },
+ {
+ "description": "property named $ref invalid",
+ "data": {"$ref": 2},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "property named $ref, containing an actual $ref",
+ "schema": {
+ "properties": {
+ "$ref": {"$ref": "#/definitions/is-string"}
+ },
+ "definitions": {
+ "is-string": {
+ "type": "string"
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "property named $ref valid",
+ "data": {"$ref": "a"},
+ "valid": true
+ },
+ {
+ "description": "property named $ref invalid",
+ "data": {"$ref": 2},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "$ref to boolean schema true",
+ "schema": {
+ "allOf": [{ "$ref": "#/definitions/bool" }],
+ "definitions": {
+ "bool": true
+ }
+ },
+ "tests": [
+ {
+ "description": "any value is valid",
+ "data": "foo",
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "$ref to boolean schema false",
+ "schema": {
+ "allOf": [{ "$ref": "#/definitions/bool" }],
+ "definitions": {
+ "bool": false
+ }
+ },
+ "tests": [
+ {
+ "description": "any value is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "Recursive references between schemas",
+ "schema": {
+ "$id": "http://localhost:1234/tree",
+ "description": "tree of nodes",
+ "type": "object",
+ "properties": {
+ "meta": {"type": "string"},
+ "nodes": {
+ "type": "array",
+ "items": {"$ref": "node"}
+ }
+ },
+ "required": ["meta", "nodes"],
+ "definitions": {
+ "node": {
+ "$id": "http://localhost:1234/node",
+ "description": "node",
+ "type": "object",
+ "properties": {
+ "value": {"type": "number"},
+ "subtree": {"$ref": "tree"}
+ },
+ "required": ["value"]
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "valid tree",
+ "data": {
+ "meta": "root",
+ "nodes": [
+ {
+ "value": 1,
+ "subtree": {
+ "meta": "child",
+ "nodes": [
+ {"value": 1.1},
+ {"value": 1.2}
+ ]
+ }
+ },
+ {
+ "value": 2,
+ "subtree": {
+ "meta": "child",
+ "nodes": [
+ {"value": 2.1},
+ {"value": 2.2}
+ ]
+ }
+ }
+ ]
+ },
+ "valid": true
+ },
+ {
+ "description": "invalid tree",
+ "data": {
+ "meta": "root",
+ "nodes": [
+ {
+ "value": 1,
+ "subtree": {
+ "meta": "child",
+ "nodes": [
+ {"value": "string is invalid"},
+ {"value": 1.2}
+ ]
+ }
+ },
+ {
+ "value": 2,
+ "subtree": {
+ "meta": "child",
+ "nodes": [
+ {"value": 2.1},
+ {"value": 2.2}
+ ]
+ }
+ }
+ ]
+ },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "refs with quote",
+ "schema": {
+ "properties": {
+ "foo\"bar": {"$ref": "#/definitions/foo%22bar"}
+ },
+ "definitions": {
+ "foo\"bar": {"type": "number"}
+ }
+ },
+ "tests": [
+ {
+ "description": "object with numbers is valid",
+ "data": {
+ "foo\"bar": 1
+ },
+ "valid": true
+ },
+ {
+ "description": "object with strings is invalid",
+ "data": {
+ "foo\"bar": "1"
+ },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "Location-independent identifier",
+ "schema": {
+ "allOf": [{
+ "$ref": "#foo"
+ }],
+ "definitions": {
+ "A": {
+ "$id": "#foo",
+ "type": "integer"
+ }
+ }
+ },
+ "tests": [
+ {
+ "data": 1,
+ "description": "match",
+ "valid": true
+ },
+ {
+ "data": "a",
+ "description": "mismatch",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "Location-independent identifier with base URI change in subschema",
+ "schema": {
+ "$id": "http://localhost:1234/root",
+ "allOf": [{
+ "$ref": "http://localhost:1234/nested.json#foo"
+ }],
+ "definitions": {
+ "A": {
+ "$id": "nested.json",
+ "definitions": {
+ "B": {
+ "$id": "#foo",
+ "type": "integer"
+ }
+ }
+ }
+ }
+ },
+ "tests": [
+ {
+ "data": 1,
+ "description": "match",
+ "valid": true
+ },
+ {
+ "data": "a",
+ "description": "mismatch",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "naive replacement of $ref with its destination is not correct",
+ "schema": {
+ "definitions": {
+ "a_string": { "type": "string" }
+ },
+ "enum": [
+ { "$ref": "#/definitions/a_string" }
+ ]
+ },
+ "tests": [
+ {
+ "description": "do not evaluate the $ref inside the enum, matching any string",
+ "data": "this is a string",
+ "valid": false
+ },
+ {
+ "description": "do not evaluate the $ref inside the enum, definition exact match",
+ "data": { "type": "string" },
+ "valid": false
+ },
+ {
+ "description": "match the enum exactly",
+ "data": { "$ref": "#/definitions/a_string" },
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "refs with relative uris and defs",
+ "schema": {
+ "$id": "http://example.com/schema-relative-uri-defs1.json",
+ "properties": {
+ "foo": {
+ "$id": "schema-relative-uri-defs2.json",
+ "definitions": {
+ "inner": {
+ "properties": {
+ "bar": { "type": "string" }
+ }
+ }
+ },
+ "allOf": [ { "$ref": "#/definitions/inner" } ]
+ }
+ },
+ "allOf": [ { "$ref": "schema-relative-uri-defs2.json" } ]
+ },
+ "tests": [
+ {
+ "description": "invalid on inner field",
+ "data": {
+ "foo": {
+ "bar": 1
+ },
+ "bar": "a"
+ },
+ "valid": false
+ },
+ {
+ "description": "invalid on outer field",
+ "data": {
+ "foo": {
+ "bar": "a"
+ },
+ "bar": 1
+ },
+ "valid": false
+ },
+ {
+ "description": "valid on both fields",
+ "data": {
+ "foo": {
+ "bar": "a"
+ },
+ "bar": "a"
+ },
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "relative refs with absolute uris and defs",
+ "schema": {
+ "$id": "http://example.com/schema-refs-absolute-uris-defs1.json",
+ "properties": {
+ "foo": {
+ "$id": "http://example.com/schema-refs-absolute-uris-defs2.json",
+ "definitions": {
+ "inner": {
+ "properties": {
+ "bar": { "type": "string" }
+ }
+ }
+ },
+ "allOf": [ { "$ref": "#/definitions/inner" } ]
+ }
+ },
+ "allOf": [ { "$ref": "schema-refs-absolute-uris-defs2.json" } ]
+ },
+ "tests": [
+ {
+ "description": "invalid on inner field",
+ "data": {
+ "foo": {
+ "bar": 1
+ },
+ "bar": "a"
+ },
+ "valid": false
+ },
+ {
+ "description": "invalid on outer field",
+ "data": {
+ "foo": {
+ "bar": "a"
+ },
+ "bar": 1
+ },
+ "valid": false
+ },
+ {
+ "description": "valid on both fields",
+ "data": {
+ "foo": {
+ "bar": "a"
+ },
+ "bar": "a"
+ },
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "$id must be resolved against nearest parent, not just immediate parent",
+ "schema": {
+ "$id": "http://example.com/a.json",
+ "definitions": {
+ "x": {
+ "$id": "http://example.com/b/c.json",
+ "not": {
+ "definitions": {
+ "y": {
+ "$id": "d.json",
+ "type": "number"
+ }
+ }
+ }
+ }
+ },
+ "allOf": [
+ {
+ "$ref": "http://example.com/b/d.json"
+ }
+ ]
+ },
+ "tests": [
+ {
+ "description": "number is valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "non-number is invalid",
+ "data": "a",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "simple URN base URI with $ref via the URN",
+ "schema": {
+ "$comment": "URIs do not have to have HTTP(s) schemes",
+ "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed",
+ "minimum": 30,
+ "properties": {
+ "foo": {"$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"}
+ }
+ },
+ "tests": [
+ {
+ "description": "valid under the URN IDed schema",
+ "data": {"foo": 37},
+ "valid": true
+ },
+ {
+ "description": "invalid under the URN IDed schema",
+ "data": {"foo": 12},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "simple URN base URI with JSON pointer",
+ "schema": {
+ "$comment": "URIs do not have to have HTTP(s) schemes",
+ "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed",
+ "properties": {
+ "foo": {"$ref": "#/definitions/bar"}
+ },
+ "definitions": {
+ "bar": {"type": "string"}
+ }
+ },
+ "tests": [
+ {
+ "description": "a string is valid",
+ "data": {"foo": "bar"},
+ "valid": true
+ },
+ {
+ "description": "a non-string is invalid",
+ "data": {"foo": 12},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "URN base URI with NSS",
+ "schema": {
+ "$comment": "RFC 8141 §2.2",
+ "$id": "urn:example:1/406/47452/2",
+ "properties": {
+ "foo": {"$ref": "#/definitions/bar"}
+ },
+ "definitions": {
+ "bar": {"type": "string"}
+ }
+ },
+ "tests": [
+ {
+ "description": "a string is valid",
+ "data": {"foo": "bar"},
+ "valid": true
+ },
+ {
+ "description": "a non-string is invalid",
+ "data": {"foo": 12},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "URN base URI with r-component",
+ "schema": {
+ "$comment": "RFC 8141 §2.3.1",
+ "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk",
+ "properties": {
+ "foo": {"$ref": "#/definitions/bar"}
+ },
+ "definitions": {
+ "bar": {"type": "string"}
+ }
+ },
+ "tests": [
+ {
+ "description": "a string is valid",
+ "data": {"foo": "bar"},
+ "valid": true
+ },
+ {
+ "description": "a non-string is invalid",
+ "data": {"foo": 12},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "URN base URI with q-component",
+ "schema": {
+ "$comment": "RFC 8141 §2.3.2",
+ "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z",
+ "properties": {
+ "foo": {"$ref": "#/definitions/bar"}
+ },
+ "definitions": {
+ "bar": {"type": "string"}
+ }
+ },
+ "tests": [
+ {
+ "description": "a string is valid",
+ "data": {"foo": "bar"},
+ "valid": true
+ },
+ {
+ "description": "a non-string is invalid",
+ "data": {"foo": 12},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "URN base URI with URN and JSON pointer ref",
+ "schema": {
+ "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed",
+ "properties": {
+ "foo": {"$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/definitions/bar"}
+ },
+ "definitions": {
+ "bar": {"type": "string"}
+ }
+ },
+ "tests": [
+ {
+ "description": "a string is valid",
+ "data": {"foo": "bar"},
+ "valid": true
+ },
+ {
+ "description": "a non-string is invalid",
+ "data": {"foo": 12},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "URN base URI with URN and anchor ref",
+ "schema": {
+ "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed",
+ "properties": {
+ "foo": {"$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"}
+ },
+ "definitions": {
+ "bar": {
+ "$id": "#something",
+ "type": "string"
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "a string is valid",
+ "data": {"foo": "bar"},
+ "valid": true
+ },
+ {
+ "description": "a non-string is invalid",
+ "data": {"foo": 12},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "ref to if",
+ "schema": {
+ "$ref": "http://example.com/ref/if",
+ "if": {
+ "$id": "http://example.com/ref/if",
+ "type": "integer"
+ }
+ },
+ "tests": [
+ {
+ "description": "a non-integer is invalid due to the $ref",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "an integer is valid",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ref to then",
+ "schema": {
+ "$ref": "http://example.com/ref/then",
+ "then": {
+ "$id": "http://example.com/ref/then",
+ "type": "integer"
+ }
+ },
+ "tests": [
+ {
+ "description": "a non-integer is invalid due to the $ref",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "an integer is valid",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "ref to else",
+ "schema": {
+ "$ref": "http://example.com/ref/else",
+ "else": {
+ "$id": "http://example.com/ref/else",
+ "type": "integer"
+ }
+ },
+ "tests": [
+ {
+ "description": "a non-integer is invalid due to the $ref",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "an integer is valid",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/refRemote.json b/tests/draft7/refRemote.json
new file mode 100644
index 0000000..c2b2002
--- /dev/null
+++ b/tests/draft7/refRemote.json
@@ -0,0 +1,239 @@
+[
+ {
+ "description": "remote ref",
+ "schema": {"$ref": "http://localhost:1234/integer.json"},
+ "tests": [
+ {
+ "description": "remote ref valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "remote ref invalid",
+ "data": "a",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "fragment within remote ref",
+ "schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"},
+ "tests": [
+ {
+ "description": "remote fragment valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "remote fragment invalid",
+ "data": "a",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "ref within remote ref",
+ "schema": {
+ "$ref": "http://localhost:1234/subSchemas.json#/refToInteger"
+ },
+ "tests": [
+ {
+ "description": "ref within ref valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "ref within ref invalid",
+ "data": "a",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "base URI change",
+ "schema": {
+ "$id": "http://localhost:1234/",
+ "items": {
+ "$id": "baseUriChange/",
+ "items": {"$ref": "folderInteger.json"}
+ }
+ },
+ "tests": [
+ {
+ "description": "base URI change ref valid",
+ "data": [[1]],
+ "valid": true
+ },
+ {
+ "description": "base URI change ref invalid",
+ "data": [["a"]],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "base URI change - change folder",
+ "schema": {
+ "$id": "http://localhost:1234/scope_change_defs1.json",
+ "type" : "object",
+ "properties": {
+ "list": {"$ref": "#/definitions/baz"}
+ },
+ "definitions": {
+ "baz": {
+ "$id": "baseUriChangeFolder/",
+ "type": "array",
+ "items": {"$ref": "folderInteger.json"}
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "number is valid",
+ "data": {"list": [1]},
+ "valid": true
+ },
+ {
+ "description": "string is invalid",
+ "data": {"list": ["a"]},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "base URI change - change folder in subschema",
+ "schema": {
+ "$id": "http://localhost:1234/scope_change_defs2.json",
+ "type" : "object",
+ "properties": {
+ "list": {"$ref": "#/definitions/baz/definitions/bar"}
+ },
+ "definitions": {
+ "baz": {
+ "$id": "baseUriChangeFolderInSubschema/",
+ "definitions": {
+ "bar": {
+ "type": "array",
+ "items": {"$ref": "folderInteger.json"}
+ }
+ }
+ }
+ }
+ },
+ "tests": [
+ {
+ "description": "number is valid",
+ "data": {"list": [1]},
+ "valid": true
+ },
+ {
+ "description": "string is invalid",
+ "data": {"list": ["a"]},
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "root ref in remote ref",
+ "schema": {
+ "$id": "http://localhost:1234/object",
+ "type": "object",
+ "properties": {
+ "name": {"$ref": "name.json#/definitions/orNull"}
+ }
+ },
+ "tests": [
+ {
+ "description": "string is valid",
+ "data": {
+ "name": "foo"
+ },
+ "valid": true
+ },
+ {
+ "description": "null is valid",
+ "data": {
+ "name": null
+ },
+ "valid": true
+ },
+ {
+ "description": "object is invalid",
+ "data": {
+ "name": {
+ "name": null
+ }
+ },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "remote ref with ref to definitions",
+ "schema": {
+ "$id": "http://localhost:1234/schema-remote-ref-ref-defs1.json",
+ "allOf": [
+ { "$ref": "ref-and-definitions.json" }
+ ]
+ },
+ "tests": [
+ {
+ "description": "invalid",
+ "data": {
+ "bar": 1
+ },
+ "valid": false
+ },
+ {
+ "description": "valid",
+ "data": {
+ "bar": "a"
+ },
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "Location-independent identifier in remote ref",
+ "schema": {
+ "$ref": "http://localhost:1234/locationIndependentIdentifierPre2019.json#/definitions/refToInteger"
+ },
+ "tests": [
+ {
+ "description": "integer is valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "string is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "retrieved nested refs resolve relative to their URI not $id",
+ "schema": {
+ "$id": "http://localhost:1234/some-id",
+ "properties": {
+ "name": {"$ref": "nested/foo-ref-string.json"}
+ }
+ },
+ "tests": [
+ {
+ "description": "number is invalid",
+ "data": {
+ "name": {"foo": 1}
+ },
+ "valid": false
+ },
+ {
+ "description": "string is valid",
+ "data": {
+ "name": {"foo": "a"}
+ },
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/required.json b/tests/draft7/required.json
new file mode 100644
index 0000000..8d8087a
--- /dev/null
+++ b/tests/draft7/required.json
@@ -0,0 +1,151 @@
+[
+ {
+ "description": "required validation",
+ "schema": {
+ "properties": {
+ "foo": {},
+ "bar": {}
+ },
+ "required": ["foo"]
+ },
+ "tests": [
+ {
+ "description": "present required property is valid",
+ "data": {"foo": 1},
+ "valid": true
+ },
+ {
+ "description": "non-present required property is invalid",
+ "data": {"bar": 1},
+ "valid": false
+ },
+ {
+ "description": "ignores arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "ignores strings",
+ "data": "",
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "required default validation",
+ "schema": {
+ "properties": {
+ "foo": {}
+ }
+ },
+ "tests": [
+ {
+ "description": "not required by default",
+ "data": {},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "required with empty array",
+ "schema": {
+ "properties": {
+ "foo": {}
+ },
+ "required": []
+ },
+ "tests": [
+ {
+ "description": "property not required",
+ "data": {},
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "required with escaped characters",
+ "schema": {
+ "required": [
+ "foo\nbar",
+ "foo\"bar",
+ "foo\\bar",
+ "foo\rbar",
+ "foo\tbar",
+ "foo\fbar"
+ ]
+ },
+ "tests": [
+ {
+ "description": "object with all properties present is valid",
+ "data": {
+ "foo\nbar": 1,
+ "foo\"bar": 1,
+ "foo\\bar": 1,
+ "foo\rbar": 1,
+ "foo\tbar": 1,
+ "foo\fbar": 1
+ },
+ "valid": true
+ },
+ {
+ "description": "object with some properties missing is invalid",
+ "data": {
+ "foo\nbar": "1",
+ "foo\"bar": "1"
+ },
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "required properties whose names are Javascript object property names",
+ "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.",
+ "schema": { "required": ["__proto__", "toString", "constructor"] },
+ "tests": [
+ {
+ "description": "ignores arrays",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "ignores other non-objects",
+ "data": 12,
+ "valid": true
+ },
+ {
+ "description": "none of the properties mentioned",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "__proto__ present",
+ "data": { "__proto__": "foo" },
+ "valid": false
+ },
+ {
+ "description": "toString present",
+ "data": { "toString": { "length": 37 } },
+ "valid": false
+ },
+ {
+ "description": "constructor present",
+ "data": { "constructor": { "length": 37 } },
+ "valid": false
+ },
+ {
+ "description": "all present",
+ "data": {
+ "__proto__": 12,
+ "toString": { "length": "foo" },
+ "constructor": 37
+ },
+ "valid": true
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/type.json b/tests/draft7/type.json
new file mode 100644
index 0000000..8304647
--- /dev/null
+++ b/tests/draft7/type.json
@@ -0,0 +1,474 @@
+[
+ {
+ "description": "integer type matches integers",
+ "schema": {"type": "integer"},
+ "tests": [
+ {
+ "description": "an integer is an integer",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "a float with zero fractional part is an integer",
+ "data": 1.0,
+ "valid": true
+ },
+ {
+ "description": "a float is not an integer",
+ "data": 1.1,
+ "valid": false
+ },
+ {
+ "description": "a string is not an integer",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "a string is still not an integer, even if it looks like one",
+ "data": "1",
+ "valid": false
+ },
+ {
+ "description": "an object is not an integer",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "an array is not an integer",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "a boolean is not an integer",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "null is not an integer",
+ "data": null,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "number type matches numbers",
+ "schema": {"type": "number"},
+ "tests": [
+ {
+ "description": "an integer is a number",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "a float with zero fractional part is a number (and an integer)",
+ "data": 1.0,
+ "valid": true
+ },
+ {
+ "description": "a float is a number",
+ "data": 1.1,
+ "valid": true
+ },
+ {
+ "description": "a string is not a number",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "a string is still not a number, even if it looks like one",
+ "data": "1",
+ "valid": false
+ },
+ {
+ "description": "an object is not a number",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "an array is not a number",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "a boolean is not a number",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "null is not a number",
+ "data": null,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "string type matches strings",
+ "schema": {"type": "string"},
+ "tests": [
+ {
+ "description": "1 is not a string",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "a float is not a string",
+ "data": 1.1,
+ "valid": false
+ },
+ {
+ "description": "a string is a string",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "a string is still a string, even if it looks like a number",
+ "data": "1",
+ "valid": true
+ },
+ {
+ "description": "an empty string is still a string",
+ "data": "",
+ "valid": true
+ },
+ {
+ "description": "an object is not a string",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "an array is not a string",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "a boolean is not a string",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "null is not a string",
+ "data": null,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "object type matches objects",
+ "schema": {"type": "object"},
+ "tests": [
+ {
+ "description": "an integer is not an object",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "a float is not an object",
+ "data": 1.1,
+ "valid": false
+ },
+ {
+ "description": "a string is not an object",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "an object is an object",
+ "data": {},
+ "valid": true
+ },
+ {
+ "description": "an array is not an object",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "a boolean is not an object",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "null is not an object",
+ "data": null,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "array type matches arrays",
+ "schema": {"type": "array"},
+ "tests": [
+ {
+ "description": "an integer is not an array",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "a float is not an array",
+ "data": 1.1,
+ "valid": false
+ },
+ {
+ "description": "a string is not an array",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "an object is not an array",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "an array is an array",
+ "data": [],
+ "valid": true
+ },
+ {
+ "description": "a boolean is not an array",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "null is not an array",
+ "data": null,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "boolean type matches booleans",
+ "schema": {"type": "boolean"},
+ "tests": [
+ {
+ "description": "an integer is not a boolean",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "zero is not a boolean",
+ "data": 0,
+ "valid": false
+ },
+ {
+ "description": "a float is not a boolean",
+ "data": 1.1,
+ "valid": false
+ },
+ {
+ "description": "a string is not a boolean",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "an empty string is not a boolean",
+ "data": "",
+ "valid": false
+ },
+ {
+ "description": "an object is not a boolean",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "an array is not a boolean",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "true is a boolean",
+ "data": true,
+ "valid": true
+ },
+ {
+ "description": "false is a boolean",
+ "data": false,
+ "valid": true
+ },
+ {
+ "description": "null is not a boolean",
+ "data": null,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "null type matches only the null object",
+ "schema": {"type": "null"},
+ "tests": [
+ {
+ "description": "an integer is not null",
+ "data": 1,
+ "valid": false
+ },
+ {
+ "description": "a float is not null",
+ "data": 1.1,
+ "valid": false
+ },
+ {
+ "description": "zero is not null",
+ "data": 0,
+ "valid": false
+ },
+ {
+ "description": "a string is not null",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "an empty string is not null",
+ "data": "",
+ "valid": false
+ },
+ {
+ "description": "an object is not null",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "an array is not null",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "true is not null",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "false is not null",
+ "data": false,
+ "valid": false
+ },
+ {
+ "description": "null is null",
+ "data": null,
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "multiple types can be specified in an array",
+ "schema": {"type": ["integer", "string"]},
+ "tests": [
+ {
+ "description": "an integer is valid",
+ "data": 1,
+ "valid": true
+ },
+ {
+ "description": "a string is valid",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "a float is invalid",
+ "data": 1.1,
+ "valid": false
+ },
+ {
+ "description": "an object is invalid",
+ "data": {},
+ "valid": false
+ },
+ {
+ "description": "an array is invalid",
+ "data": [],
+ "valid": false
+ },
+ {
+ "description": "a boolean is invalid",
+ "data": true,
+ "valid": false
+ },
+ {
+ "description": "null is invalid",
+ "data": null,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "type as array with one item",
+ "schema": {
+ "type": ["string"]
+ },
+ "tests": [
+ {
+ "description": "string is valid",
+ "data": "foo",
+ "valid": true
+ },
+ {
+ "description": "number is invalid",
+ "data": 123,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "type: array or object",
+ "schema": {
+ "type": ["array", "object"]
+ },
+ "tests": [
+ {
+ "description": "array is valid",
+ "data": [1,2,3],
+ "valid": true
+ },
+ {
+ "description": "object is valid",
+ "data": {"foo": 123},
+ "valid": true
+ },
+ {
+ "description": "number is invalid",
+ "data": 123,
+ "valid": false
+ },
+ {
+ "description": "string is invalid",
+ "data": "foo",
+ "valid": false
+ },
+ {
+ "description": "null is invalid",
+ "data": null,
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "type: array, object or null",
+ "schema": {
+ "type": ["array", "object", "null"]
+ },
+ "tests": [
+ {
+ "description": "array is valid",
+ "data": [1,2,3],
+ "valid": true
+ },
+ {
+ "description": "object is valid",
+ "data": {"foo": 123},
+ "valid": true
+ },
+ {
+ "description": "null is valid",
+ "data": null,
+ "valid": true
+ },
+ {
+ "description": "number is invalid",
+ "data": 123,
+ "valid": false
+ },
+ {
+ "description": "string is invalid",
+ "data": "foo",
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/uniqueItems.json b/tests/draft7/uniqueItems.json
new file mode 100644
index 0000000..2ccf666
--- /dev/null
+++ b/tests/draft7/uniqueItems.json
@@ -0,0 +1,404 @@
+[
+ {
+ "description": "uniqueItems validation",
+ "schema": {"uniqueItems": true},
+ "tests": [
+ {
+ "description": "unique array of integers is valid",
+ "data": [1, 2],
+ "valid": true
+ },
+ {
+ "description": "non-unique array of integers is invalid",
+ "data": [1, 1],
+ "valid": false
+ },
+ {
+ "description": "non-unique array of more than two integers is invalid",
+ "data": [1, 2, 1],
+ "valid": false
+ },
+ {
+ "description": "numbers are unique if mathematically unequal",
+ "data": [1.0, 1.00, 1],
+ "valid": false
+ },
+ {
+ "description": "false is not equal to zero",
+ "data": [0, false],
+ "valid": true
+ },
+ {
+ "description": "true is not equal to one",
+ "data": [1, true],
+ "valid": true
+ },
+ {
+ "description": "unique array of strings is valid",
+ "data": ["foo", "bar", "baz"],
+ "valid": true
+ },
+ {
+ "description": "non-unique array of strings is invalid",
+ "data": ["foo", "bar", "foo"],
+ "valid": false
+ },
+ {
+ "description": "unique array of objects is valid",
+ "data": [{"foo": "bar"}, {"foo": "baz"}],
+ "valid": true
+ },
+ {
+ "description": "non-unique array of objects is invalid",
+ "data": [{"foo": "bar"}, {"foo": "bar"}],
+ "valid": false
+ },
+ {
+ "description": "unique array of nested objects is valid",
+ "data": [
+ {"foo": {"bar" : {"baz" : true}}},
+ {"foo": {"bar" : {"baz" : false}}}
+ ],
+ "valid": true
+ },
+ {
+ "description": "non-unique array of nested objects is invalid",
+ "data": [
+ {"foo": {"bar" : {"baz" : true}}},
+ {"foo": {"bar" : {"baz" : true}}}
+ ],
+ "valid": false
+ },
+ {
+ "description": "unique array of arrays is valid",
+ "data": [["foo"], ["bar"]],
+ "valid": true
+ },
+ {
+ "description": "non-unique array of arrays is invalid",
+ "data": [["foo"], ["foo"]],
+ "valid": false
+ },
+ {
+ "description": "non-unique array of more than two arrays is invalid",
+ "data": [["foo"], ["bar"], ["foo"]],
+ "valid": false
+ },
+ {
+ "description": "1 and true are unique",
+ "data": [1, true],
+ "valid": true
+ },
+ {
+ "description": "0 and false are unique",
+ "data": [0, false],
+ "valid": true
+ },
+ {
+ "description": "[1] and [true] are unique",
+ "data": [[1], [true]],
+ "valid": true
+ },
+ {
+ "description": "[0] and [false] are unique",
+ "data": [[0], [false]],
+ "valid": true
+ },
+ {
+ "description": "nested [1] and [true] are unique",
+ "data": [[[1], "foo"], [[true], "foo"]],
+ "valid": true
+ },
+ {
+ "description": "nested [0] and [false] are unique",
+ "data": [[[0], "foo"], [[false], "foo"]],
+ "valid": true
+ },
+ {
+ "description": "unique heterogeneous types are valid",
+ "data": [{}, [1], true, null, 1, "{}"],
+ "valid": true
+ },
+ {
+ "description": "non-unique heterogeneous types are invalid",
+ "data": [{}, [1], true, null, {}, 1],
+ "valid": false
+ },
+ {
+ "description": "different objects are unique",
+ "data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}],
+ "valid": true
+ },
+ {
+ "description": "objects are non-unique despite key order",
+ "data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}],
+ "valid": false
+ },
+ {
+ "description": "{\"a\": false} and {\"a\": 0} are unique",
+ "data": [{"a": false}, {"a": 0}],
+ "valid": true
+ },
+ {
+ "description": "{\"a\": true} and {\"a\": 1} are unique",
+ "data": [{"a": true}, {"a": 1}],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "uniqueItems with an array of items",
+ "schema": {
+ "items": [{"type": "boolean"}, {"type": "boolean"}],
+ "uniqueItems": true
+ },
+ "tests": [
+ {
+ "description": "[false, true] from items array is valid",
+ "data": [false, true],
+ "valid": true
+ },
+ {
+ "description": "[true, false] from items array is valid",
+ "data": [true, false],
+ "valid": true
+ },
+ {
+ "description": "[false, false] from items array is not valid",
+ "data": [false, false],
+ "valid": false
+ },
+ {
+ "description": "[true, true] from items array is not valid",
+ "data": [true, true],
+ "valid": false
+ },
+ {
+ "description": "unique array extended from [false, true] is valid",
+ "data": [false, true, "foo", "bar"],
+ "valid": true
+ },
+ {
+ "description": "unique array extended from [true, false] is valid",
+ "data": [true, false, "foo", "bar"],
+ "valid": true
+ },
+ {
+ "description": "non-unique array extended from [false, true] is not valid",
+ "data": [false, true, "foo", "foo"],
+ "valid": false
+ },
+ {
+ "description": "non-unique array extended from [true, false] is not valid",
+ "data": [true, false, "foo", "foo"],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "uniqueItems with an array of items and additionalItems=false",
+ "schema": {
+ "items": [{"type": "boolean"}, {"type": "boolean"}],
+ "uniqueItems": true,
+ "additionalItems": false
+ },
+ "tests": [
+ {
+ "description": "[false, true] from items array is valid",
+ "data": [false, true],
+ "valid": true
+ },
+ {
+ "description": "[true, false] from items array is valid",
+ "data": [true, false],
+ "valid": true
+ },
+ {
+ "description": "[false, false] from items array is not valid",
+ "data": [false, false],
+ "valid": false
+ },
+ {
+ "description": "[true, true] from items array is not valid",
+ "data": [true, true],
+ "valid": false
+ },
+ {
+ "description": "extra items are invalid even if unique",
+ "data": [false, true, null],
+ "valid": false
+ }
+ ]
+ },
+ {
+ "description": "uniqueItems=false validation",
+ "schema": { "uniqueItems": false },
+ "tests": [
+ {
+ "description": "unique array of integers is valid",
+ "data": [1, 2],
+ "valid": true
+ },
+ {
+ "description": "non-unique array of integers is valid",
+ "data": [1, 1],
+ "valid": true
+ },
+ {
+ "description": "numbers are unique if mathematically unequal",
+ "data": [1.0, 1.00, 1],
+ "valid": true
+ },
+ {
+ "description": "false is not equal to zero",
+ "data": [0, false],
+ "valid": true
+ },
+ {
+ "description": "true is not equal to one",
+ "data": [1, true],
+ "valid": true
+ },
+ {
+ "description": "unique array of objects is valid",
+ "data": [{"foo": "bar"}, {"foo": "baz"}],
+ "valid": true
+ },
+ {
+ "description": "non-unique array of objects is valid",
+ "data": [{"foo": "bar"}, {"foo": "bar"}],
+ "valid": true
+ },
+ {
+ "description": "unique array of nested objects is valid",
+ "data": [
+ {"foo": {"bar" : {"baz" : true}}},
+ {"foo": {"bar" : {"baz" : false}}}
+ ],
+ "valid": true
+ },
+ {
+ "description": "non-unique array of nested objects is valid",
+ "data": [
+ {"foo": {"bar" : {"baz" : true}}},
+ {"foo": {"bar" : {"baz" : true}}}
+ ],
+ "valid": true
+ },
+ {
+ "description": "unique array of arrays is valid",
+ "data": [["foo"], ["bar"]],
+ "valid": true
+ },
+ {
+ "description": "non-unique array of arrays is valid",
+ "data": [["foo"], ["foo"]],
+ "valid": true
+ },
+ {
+ "description": "1 and true are unique",
+ "data": [1, true],
+ "valid": true
+ },
+ {
+ "description": "0 and false are unique",
+ "data": [0, false],
+ "valid": true
+ },
+ {
+ "description": "unique heterogeneous types are valid",
+ "data": [{}, [1], true, null, 1],
+ "valid": true
+ },
+ {
+ "description": "non-unique heterogeneous types are valid",
+ "data": [{}, [1], true, null, {}, 1],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "uniqueItems=false with an array of items",
+ "schema": {
+ "items": [{"type": "boolean"}, {"type": "boolean"}],
+ "uniqueItems": false
+ },
+ "tests": [
+ {
+ "description": "[false, true] from items array is valid",
+ "data": [false, true],
+ "valid": true
+ },
+ {
+ "description": "[true, false] from items array is valid",
+ "data": [true, false],
+ "valid": true
+ },
+ {
+ "description": "[false, false] from items array is valid",
+ "data": [false, false],
+ "valid": true
+ },
+ {
+ "description": "[true, true] from items array is valid",
+ "data": [true, true],
+ "valid": true
+ },
+ {
+ "description": "unique array extended from [false, true] is valid",
+ "data": [false, true, "foo", "bar"],
+ "valid": true
+ },
+ {
+ "description": "unique array extended from [true, false] is valid",
+ "data": [true, false, "foo", "bar"],
+ "valid": true
+ },
+ {
+ "description": "non-unique array extended from [false, true] is valid",
+ "data": [false, true, "foo", "foo"],
+ "valid": true
+ },
+ {
+ "description": "non-unique array extended from [true, false] is valid",
+ "data": [true, false, "foo", "foo"],
+ "valid": true
+ }
+ ]
+ },
+ {
+ "description": "uniqueItems=false with an array of items and additionalItems=false",
+ "schema": {
+ "items": [{"type": "boolean"}, {"type": "boolean"}],
+ "uniqueItems": false,
+ "additionalItems": false
+ },
+ "tests": [
+ {
+ "description": "[false, true] from items array is valid",
+ "data": [false, true],
+ "valid": true
+ },
+ {
+ "description": "[true, false] from items array is valid",
+ "data": [true, false],
+ "valid": true
+ },
+ {
+ "description": "[false, false] from items array is valid",
+ "data": [false, false],
+ "valid": true
+ },
+ {
+ "description": "[true, true] from items array is valid",
+ "data": [true, true],
+ "valid": true
+ },
+ {
+ "description": "extra items are invalid even if unique",
+ "data": [false, true, null],
+ "valid": false
+ }
+ ]
+ }
+]
diff --git a/tests/draft7/unknownKeyword.json b/tests/draft7/unknownKeyword.json
new file mode 100644
index 0000000..1f58d97
--- /dev/null
+++ b/tests/draft7/unknownKeyword.json
@@ -0,0 +1,56 @@
+[
+ {
+ "description": "$id inside an unknown keyword is not a real identifier",
+ "comment": "the implementation must not be confused by an $id in locations we do not know how to parse",
+ "schema": {
+ "definitions": {
+ "id_in_unknown0": {
+ "not": {
+ "array_of_schemas": [
+ {
+ "$id": "https://localhost:1234/unknownKeyword/my_identifier.json",
+ "type": "null"
+ }
+ ]
+ }
+ },
+ "real_id_in_schema": {
+ "$id": "https://localhost:1234/unknownKeyword/my_identifier.json",
+ "type": "string"
+ },
+ "id_in_unknown1": {
+ "not": {
+ "object_of_schemas": {
+ "foo": {
+ "$id": "https://localhost:1234/unknownKeyword/my_identifier.json",
+ "type": "integer"
+ }
+ }
+ }
+ }
+ },
+ "anyOf": [
+ { "$ref": "#/definitions/id_in_unknown0" },
+ { "$ref": "#/definitions/id_in_unknown1" },
+ { "$ref": "https://localhost:1234/unknownKeyword/my_identifier.json" }
+ ]
+ },
+ "tests": [
+ {
+ "description": "type matches second anyOf, which has a real schema in it",
+ "data": "a string",
+ "valid": true
+ },
+ {
+ "description": "type matches non-schema in first anyOf",
+ "data": null,
+ "valid": false
+ },
+ {
+ "description": "type matches non-schema in third anyOf",
+ "data": 1,
+ "valid": false
+ }
+ ]
+ }
+]