diff --git a/src/string-format-check.cpp b/src/string-format-check.cpp index 8bae0e2..28a818c 100644 --- a/src/string-format-check.cpp +++ b/src/string-format-check.cpp @@ -68,21 +68,28 @@ void rfc3339_time_check(const std::string &value) range_check(hour, 0, 23); range_check(minute, 0, 59); + + int offsetHour = 0, + offsetMinute = 0; + + /* don't check the numerical offset if time zone is specified as 'Z' */ + if (!matches[5].str().empty()) { + offsetHour = std::stoi(matches[5].str()); + offsetMinute = std::stoi(matches[6].str()); + + range_check(offsetHour, -23, 23); + range_check(offsetMinute, 0, 59); + } + /** * @todo Could be made more exact by querying a leap second database and choosing the * correct maximum in {58,59,60}. This current solution might match some invalid dates * but it won't lead to false negatives. This only works if we know the full date, however */ - range_check(second, 0, 60); - - /* don't check the numerical offset if time zone is specified as 'Z' */ - if (!matches[5].str().empty()) { - const auto offsetHour = std::stoi(matches[5].str()); - const auto offsetMinute = std::stoi(matches[6].str()); - - range_check(offsetHour, -23, 23); - range_check(offsetMinute, 0, 59); - } + if (((hour - offsetHour) % 24) == 23 && ((minute - offsetMinute) % 60) == 59) + range_check(second, 0, 60); // possible leap-second + else + range_check(second, 0, 59); } /** @@ -124,7 +131,7 @@ void rfc3339_date_time_check(const std::string &value) rfc3339_time_check(matches[2].str()); } -const std::string decOctet{R"((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))"}; // matches numbers 0-255 +const std::string decOctet{R"((?:25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9]))"}; // matches numbers 0-255 const std::string ipv4Address{"(?:" + decOctet + R"(\.){3})" + decOctet}; const std::string h16{R"([0-9A-Fa-f]{1,4})"}; const std::string h16Left{"(?:" + h16 + ":)"}; diff --git a/test/JSON-Schema-Test-Suite/CMakeLists.txt b/test/JSON-Schema-Test-Suite/CMakeLists.txt index 61d5fd4..d0d502a 100644 --- a/test/JSON-Schema-Test-Suite/CMakeLists.txt +++ b/test/JSON-Schema-Test-Suite/CMakeLists.txt @@ -52,8 +52,9 @@ if(JSON_SCHEMA_TEST_SUITE_PATH) JSON-Suite::Optional::bignum JSON-Suite::Optional::zeroTerminatedFloats JSON-Suite::Optional::non-bmp-regex + JSON-Suite::Optional::float-overflow - JSON-Suite::Optional::Format::ecmascript-regex + JSON-Suite::Optional::ecmascript-regex JSON-Suite::Optional::Format::idn-email JSON-Suite::Optional::Format::idn-hostname JSON-Suite::Optional::Format::iri-reference diff --git a/test/JSON-Schema-Test-Suite/remotes/baseUriChange/folderInteger.json b/test/JSON-Schema-Test-Suite/remotes/baseUriChange/folderInteger.json new file mode 100644 index 0000000..8b50ea3 --- /dev/null +++ b/test/JSON-Schema-Test-Suite/remotes/baseUriChange/folderInteger.json @@ -0,0 +1,3 @@ +{ + "type": "integer" +} diff --git a/test/JSON-Schema-Test-Suite/remotes/baseUriChangeFolder/folderInteger.json b/test/JSON-Schema-Test-Suite/remotes/baseUriChangeFolder/folderInteger.json new file mode 100644 index 0000000..8b50ea3 --- /dev/null +++ b/test/JSON-Schema-Test-Suite/remotes/baseUriChangeFolder/folderInteger.json @@ -0,0 +1,3 @@ +{ + "type": "integer" +} diff --git a/test/JSON-Schema-Test-Suite/remotes/baseUriChangeFolderInSubschema/folderInteger.json b/test/JSON-Schema-Test-Suite/remotes/baseUriChangeFolderInSubschema/folderInteger.json new file mode 100644 index 0000000..8b50ea3 --- /dev/null +++ b/test/JSON-Schema-Test-Suite/remotes/baseUriChangeFolderInSubschema/folderInteger.json @@ -0,0 +1,3 @@ +{ + "type": "integer" +} diff --git a/test/JSON-Schema-Test-Suite/remotes/ref-and-definitions.json b/test/JSON-Schema-Test-Suite/remotes/ref-and-definitions.json new file mode 100644 index 0000000..e0ee802 --- /dev/null +++ b/test/JSON-Schema-Test-Suite/remotes/ref-and-definitions.json @@ -0,0 +1,11 @@ +{ + "$id": "http://localhost:1234/ref-and-definitions.json", + "definitions": { + "inner": { + "properties": { + "bar": { "type": "string" } + } + } + }, + "allOf": [ { "$ref": "#/definitions/inner" } ] +} diff --git a/test/JSON-Schema-Test-Suite/remotes/ref-and-defs.json b/test/JSON-Schema-Test-Suite/remotes/ref-and-defs.json new file mode 100644 index 0000000..85d06c3 --- /dev/null +++ b/test/JSON-Schema-Test-Suite/remotes/ref-and-defs.json @@ -0,0 +1,11 @@ +{ + "$id": "http://localhost:1234/ref-and-defs.json", + "$defs": { + "inner": { + "properties": { + "bar": { "type": "string" } + } + } + }, + "$ref": "#/$defs/inner" +} diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/additionalItems.json b/test/JSON-Schema-Test-Suite/tests/draft7/additionalItems.json index abecc57..784bc84 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/additionalItems.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/additionalItems.json @@ -19,7 +19,7 @@ ] }, { - "description": "items is schema, no additionalItems", + "description": "when items is schema, additionalItems does nothing", "schema": { "items": {}, "additionalItems": false @@ -33,14 +33,24 @@ ] }, { - "description": "array of items with no additionalItems", + "description": "array of items with no additionalItems permitted", "schema": { "items": [{}, {}, {}], "additionalItems": false }, "tests": [ { - "description": "fewer number of items present", + "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 }, @@ -83,5 +93,57 @@ "valid": true } ] + }, + { + "description": "additionalItems should 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 should 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 + } + ] } ] diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/additionalProperties.json b/test/JSON-Schema-Test-Suite/tests/draft7/additionalProperties.json index ffeac6b..381275a 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/additionalProperties.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/additionalProperties.json @@ -124,7 +124,7 @@ }, "tests": [ { - "description": "properties defined in allOf are not allowed", + "description": "properties defined in allOf are not examined", "data": {"foo": 1, "bar": true}, "valid": false } diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/allOf.json b/test/JSON-Schema-Test-Suite/tests/draft7/allOf.json index cff8251..ec9319e 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/allOf.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/allOf.json @@ -240,5 +240,55 @@ "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/test/JSON-Schema-Test-Suite/tests/draft7/const.json b/test/JSON-Schema-Test-Suite/tests/draft7/const.json index 1a55235..1c2cafc 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/const.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/const.json @@ -125,6 +125,90 @@ } ] }, + { + "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}, @@ -238,5 +322,21 @@ "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/test/JSON-Schema-Test-Suite/tests/draft7/contains.json b/test/JSON-Schema-Test-Suite/tests/draft7/contains.json index 67ecbd9..c5471cc 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/contains.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/contains.json @@ -96,5 +96,34 @@ "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 + } + ] } ] diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/default.json b/test/JSON-Schema-Test-Suite/tests/draft7/default.json index 1762977..289a9b6 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/default.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/default.json @@ -45,5 +45,35 @@ "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/test/JSON-Schema-Test-Suite/tests/draft7/definitions.json b/test/JSON-Schema-Test-Suite/tests/draft7/definitions.json index 4360406..afe396e 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/definitions.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/definitions.json @@ -1,6 +1,6 @@ [ { - "description": "valid definition", + "description": "validate definition against metaschema", "schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, "tests": [ { @@ -11,13 +11,7 @@ } }, "valid": true - } - ] - }, - { - "description": "invalid definition", - "schema": {"$ref": "http://json-schema.org/draft-07/schema#"}, - "tests": [ + }, { "description": "invalid definition schema", "data": { diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/enum.json b/test/JSON-Schema-Test-Suite/tests/draft7/enum.json index 0191b55..f085097 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/enum.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/enum.json @@ -33,6 +33,16 @@ "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 } ] }, @@ -206,5 +216,21 @@ "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/test/JSON-Schema-Test-Suite/tests/draft7/id.json b/test/JSON-Schema-Test-Suite/tests/draft7/id.json new file mode 100644 index 0000000..b58e0d0 --- /dev/null +++ b/test/JSON-Schema-Test-Suite/tests/draft7/id.json @@ -0,0 +1,53 @@ +[ + { + "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 + } + ] + } + +] diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/if-then-else.json b/test/JSON-Schema-Test-Suite/tests/draft7/if-then-else.json index be73281..284e919 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/if-then-else.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/if-then-else.json @@ -184,5 +184,75 @@ "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/test/JSON-Schema-Test-Suite/tests/draft7/infinite-loop-detection.json b/test/JSON-Schema-Test-Suite/tests/draft7/infinite-loop-detection.json new file mode 100644 index 0000000..f98c74f --- /dev/null +++ b/test/JSON-Schema-Test-Suite/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/test/JSON-Schema-Test-Suite/tests/draft7/maxProperties.json b/test/JSON-Schema-Test-Suite/tests/draft7/maxProperties.json index 513731e..aa7209f 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/maxProperties.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/maxProperties.json @@ -34,5 +34,21 @@ "valid": true } ] + }, + { + "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/test/JSON-Schema-Test-Suite/tests/draft7/multipleOf.json b/test/JSON-Schema-Test-Suite/tests/draft7/multipleOf.json index ca3b761..faa87cf 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/multipleOf.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/multipleOf.json @@ -56,5 +56,16 @@ "valid": false } ] + }, + { + "description": "invalid instance should not raise error when 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/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ecmascript-regex.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/ecmascript-regex.json similarity index 63% rename from test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ecmascript-regex.json rename to test/JSON-Schema-Test-Suite/tests/draft7/optional/ecmascript-regex.json index 106c33b..6ed6cbe 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ecmascript-regex.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/ecmascript-regex.json @@ -1,15 +1,4 @@ [ - { - "description": "ECMA 262 regex non-compliance", - "schema": { "format": "regex" }, - "tests": [ - { - "description": "ECMA 262 has no support for \\Z anchor from .NET", - "data": "^\\S(|(.|\\n)*\\S)\\Z", - "valid": false - } - ] - }, { "description": "ECMA 262 regex $ does not match trailing newline", "schema": { @@ -154,7 +143,7 @@ ] }, { - "description": "ECMA 262 \\w matches everything but ascii letters", + "description": "ECMA 262 \\W matches everything but ascii letters", "schema": { "type": "string", "pattern": "^\\W$" @@ -173,7 +162,7 @@ ] }, { - "description": "ECMA 262 \\s matches ascii whitespace only", + "description": "ECMA 262 \\s matches whitespace", "schema": { "type": "string", "pattern": "^\\s$" @@ -185,14 +174,59 @@ "valid": true }, { - "description": "latin-1 non-breaking-space does not match (unlike e.g. Python)", + "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 ascii whitespace", + "description": "ECMA 262 \\S matches everything but whitespace", "schema": { "type": "string", "pattern": "^\\S$" @@ -204,8 +238,53 @@ "valid": false }, { - "description": "latin-1 non-breaking-space matches (unlike e.g. Python)", + "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 } ] diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/optional/float-overflow.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/float-overflow.json new file mode 100644 index 0000000..52ff982 --- /dev/null +++ b/test/JSON-Schema-Test-Suite/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/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/date-time.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/date-time.json index dfccee6..900fcb7 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/date-time.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/date-time.json @@ -47,6 +47,16 @@ "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 } ] } diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/date.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/date.json index cd23baa..453b51d 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/date.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/date.json @@ -17,6 +17,16 @@ "description": "only RFC3339 not all of ISO 8601 are valid", "data": "2013-350", "valid": false + }, + { + "description": "invalidates non-padded month dates", + "data": "1998-1-20", + "valid": false + }, + { + "description": "invalidates non-padded day dates", + "data": "1998-01-1", + "valid": false } ] } diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/email.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/email.json index c837c84..02396d2 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/email.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/email.json @@ -12,6 +12,41 @@ "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/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/hostname.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/hostname.json index d22e57d..476541a 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/hostname.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/hostname.json @@ -27,6 +27,41 @@ "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/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/idn-email.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/idn-email.json index 637409e..552d106 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/idn-email.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/idn-email.json @@ -12,6 +12,16 @@ "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/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/idn-hostname.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/idn-hostname.json index 3291820..7f10bd8 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/idn-hostname.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/idn-hostname.json @@ -22,6 +22,252 @@ "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/rfc/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/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ipv4.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ipv4.json index 661148a..e36a381 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ipv4.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ipv4.json @@ -27,6 +27,22 @@ "description": "an IP address as an integer", "data": "0x7f000001", "valid": false + }, + { + "description": "an IP address as an integer (decimal)", + "data": "2130706433", + "valid": false + }, + { + "description": "leading zeroes should be rejected, 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 } ] } diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ipv6.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ipv6.json index f67559b..2a08cb4 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ipv6.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/ipv6.json @@ -22,6 +22,131 @@ "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": "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 } ] } diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/iri.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/iri.json index ed54094..1414f2e 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/iri.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/iri.json @@ -9,7 +9,7 @@ "valid": true }, { - "description": "a valid IRI with anchor tag and parantheses", + "description": "a valid IRI with anchor tag and parentheses", "data": "http://ƒøø.com/blah_(wîkïpédiå)_blah#ßité-1", "valid": true }, diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/time.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/time.json index 4ec8a01..74e8bf9 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/time.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/time.json @@ -5,9 +5,84 @@ "tests": [ { "description": "a valid time string", + "data": "08:30:06Z", + "valid": true + }, + { + "description": "a valid time string with leap second", + "data": "23:59:60Z", + "valid": true + }, + { + "description": "a valid time string with leap second with offset", + "data": "15:59:60-08:00", + "valid": true + }, + { + "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 time string", "data": "08:30:06 PST", diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/uri.json b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/uri.json index 25cc40c..58d3085 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/uri.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/optional/format/uri.json @@ -9,7 +9,7 @@ "valid": true }, { - "description": "a valid URL with anchor tag and parantheses", + "description": "a valid URL with anchor tag and parentheses", "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", "valid": true }, @@ -97,6 +97,11 @@ "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/test/JSON-Schema-Test-Suite/tests/draft7/patternProperties.json b/test/JSON-Schema-Test-Suite/tests/draft7/patternProperties.json index 1d04a16..c10ffcc 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/patternProperties.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/patternProperties.json @@ -141,6 +141,11 @@ "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": {}, diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/ref.json b/test/JSON-Schema-Test-Suite/tests/draft7/ref.json index 44b8ed2..406ae16 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/ref.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/ref.json @@ -75,13 +75,15 @@ { "description": "escaped pointer ref", "schema": { - "tilda~field": {"type": "integer"}, - "slash/field": {"type": "integer"}, - "percent%field": {"type": "integer"}, + "definitions": { + "tilde~field": {"type": "integer"}, + "slash/field": {"type": "integer"}, + "percent%field": {"type": "integer"} + }, "properties": { - "tilda": {"$ref": "#/tilda~0field"}, - "slash": {"$ref": "#/slash~1field"}, - "percent": {"$ref": "#/percent%25field"} + "tilde": {"$ref": "#/definitions/tilde~0field"}, + "slash": {"$ref": "#/definitions/slash~1field"}, + "percent": {"$ref": "#/definitions/percent%25field"} } }, "tests": [ @@ -91,8 +93,8 @@ "valid": false }, { - "description": "tilda invalid", - "data": {"tilda": "aoeu"}, + "description": "tilde invalid", + "data": {"tilde": "aoeu"}, "valid": false }, { @@ -106,8 +108,8 @@ "valid": true }, { - "description": "tilda valid", - "data": {"tilda": 123}, + "description": "tilde valid", + "data": {"tilde": 123}, "valid": true }, { @@ -125,7 +127,7 @@ "b": {"$ref": "#/definitions/a"}, "c": {"$ref": "#/definitions/b"} }, - "$ref": "#/definitions/c" + "allOf": [{ "$ref": "#/definitions/c" }] }, "tests": [ { @@ -209,10 +211,35 @@ } ] }, + { + "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": { - "$ref": "#/definitions/bool", + "allOf": [{ "$ref": "#/definitions/bool" }], "definitions": { "bool": true } @@ -228,7 +255,7 @@ { "description": "$ref to boolean schema false", "schema": { - "$ref": "#/definitions/bool", + "allOf": [{ "$ref": "#/definitions/bool" }], "definitions": { "bool": false } @@ -382,32 +409,6 @@ } ] }, - { - "description": "Location-independent identifier with absolute URI", - "schema": { - "allOf": [{ - "$ref": "http://localhost:1234/bar#foo" - }], - "definitions": { - "A": { - "$id": "http://localhost:1234/bar#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": { @@ -439,5 +440,137 @@ "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 + } + ] } ] diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/refRemote.json b/test/JSON-Schema-Test-Suite/tests/draft7/refRemote.json index 819d326..9d8057b 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/refRemote.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/refRemote.json @@ -54,7 +54,7 @@ "schema": { "$id": "http://localhost:1234/", "items": { - "$id": "folder/", + "$id": "baseUriChange/", "items": {"$ref": "folderInteger.json"} } }, @@ -81,7 +81,7 @@ }, "definitions": { "baz": { - "$id": "folder/", + "$id": "baseUriChangeFolder/", "type": "array", "items": {"$ref": "folderInteger.json"} } @@ -110,7 +110,7 @@ }, "definitions": { "baz": { - "$id": "folder/", + "$id": "baseUriChangeFolderInSubschema/", "definitions": { "bar": { "type": "array", @@ -167,5 +167,28 @@ "valid": false } ] + }, + { + "description": "remote ref with ref to definitions", + "schema": { + "$id": "http://localhost:1234/schema-remote-ref-ref-defs1.json", + "$ref": "ref-and-definitions.json" + }, + "tests": [ + { + "description": "invalid", + "data": { + "bar": 1 + }, + "valid": false + }, + { + "description": "valid", + "data": { + "bar": "a" + }, + "valid": true + } + ] } ] diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/uniqueItems.json b/test/JSON-Schema-Test-Suite/tests/draft7/uniqueItems.json index ea256a0..4846c77 100644 --- a/test/JSON-Schema-Test-Suite/tests/draft7/uniqueItems.json +++ b/test/JSON-Schema-Test-Suite/tests/draft7/uniqueItems.json @@ -74,15 +74,55 @@ "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], + "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 } ] }, diff --git a/test/JSON-Schema-Test-Suite/tests/draft7/unknownKeyword.json b/test/JSON-Schema-Test-Suite/tests/draft7/unknownKeyword.json new file mode 100644 index 0000000..1f58d97 --- /dev/null +++ b/test/JSON-Schema-Test-Suite/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 + } + ] + } +] diff --git a/test/string-format-check-test.cpp b/test/string-format-check-test.cpp index c6954a2..2a5fb88 100644 --- a/test/string-format-check-test.cpp +++ b/test/string-format-check-test.cpp @@ -54,7 +54,8 @@ int main() {"2020-02-29T11:11:11+01:00", true}, {"2020-02-30T11:11:11+01:00", false}, {"2020-02-29T23:59:59+01:00", true}, - {"2020-02-29T23:59:60+01:00", true}, + {"2020-02-29T23:59:60+01:00", false}, + {"2020-02-29T23:59:60+00:00", true}, {"2020-02-29T23:60:59+01:00", false}, {"2019-09-30T11:11:11+01:00", true}, {"2019-09-31T11:11:11+01:00", false},