Complete rewrite of the validator - aiming a 2.0-release
Schema a now "parsed" into C++-validator-objects in a first step and then validation takes place with these objects. Errors are now handled via a user-provided error-handler allowing the user to collect all errors at once or bail out when a certain threshold is reached. Fixes #36 and #8. One (sub-)schema can now be referenced with different URIs. Fixes #9 JSON schema draft 7 is now supported. Fixes #35
This commit is contained in:
parent
2785ce0c64
commit
7beb40bc61
@ -7,9 +7,11 @@ AllowShortFunctionsOnASingleLine: Inline
|
||||
BreakBeforeBraces: Linux
|
||||
ColumnLimit: 0
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
IndentWidth: 2
|
||||
ObjCBlockIndentWidth: 2
|
||||
IndentWidth: 4
|
||||
IndentPPDirectives: AfterHash
|
||||
ObjCBlockIndentWidth: 0
|
||||
SpaceAfterCStyleCast: true
|
||||
TabWidth: 2
|
||||
TabWidth: 4
|
||||
AccessModifierOffset: -4
|
||||
UseTab: ForIndentation
|
||||
...
|
||||
|
||||
@ -60,7 +60,7 @@ script:
|
||||
- $CXX --version
|
||||
|
||||
# put json.hpp to nlohmann
|
||||
- mkdir -p nlohmann && wget https://github.com/nlohmann/json/releases/download/v3.1.2/json.hpp -O nlohmann/json.hpp
|
||||
- mkdir -p nlohmann && wget https://github.com/nlohmann/json/releases/download/v3.5.0/json.hpp -O nlohmann/json.hpp
|
||||
|
||||
# compile and execute unit tests
|
||||
- mkdir -p build && cd build
|
||||
|
||||
@ -32,7 +32,7 @@ endif()
|
||||
|
||||
# and one for the validator
|
||||
add_library(json-schema-validator
|
||||
src/json-schema-draft4.json.cpp
|
||||
src/json-schema-draft7.json.cpp
|
||||
src/json-uri.cpp
|
||||
src/json-validator.cpp)
|
||||
|
||||
@ -95,8 +95,13 @@ if (BUILD_EXAMPLES)
|
||||
# simple json-schema-validator-executable
|
||||
add_executable(json-schema-validate app/json-schema-validate.cpp)
|
||||
target_link_libraries(json-schema-validate json-schema-validator)
|
||||
|
||||
add_executable(readme app/readme.cpp)
|
||||
target_link_libraries(readme json-schema-validator)
|
||||
endif()
|
||||
|
||||
#add_subdirectory(ng)
|
||||
|
||||
if (BUILD_TESTS)
|
||||
# test-zone
|
||||
enable_testing()
|
||||
|
||||
134
README.md
134
README.md
@ -1,53 +1,68 @@
|
||||
|
||||
[](https://travis-ci.org/pboettch/json-schema-validator)
|
||||
|
||||
# Modern C++ JSON schema validator
|
||||
# JSON schema validator for JSON for Modern C++
|
||||
|
||||
# What is it?
|
||||
|
||||
This is a C++ library for validating JSON documents based on a
|
||||
[JSON Schema](http://json-schema.org/) which itself should validate with
|
||||
[draft-4 of JSON Schema Validation](http://json-schema.org/schema).
|
||||
[draft-7 of JSON Schema Validation](http://json-schema.org/schema).
|
||||
|
||||
First a disclaimer: *It is work in progress and
|
||||
contributions or hints or discussions are welcome.*
|
||||
contributions or hints or discussions are welcome.* Even though a 2.0.0 release is immenent.
|
||||
|
||||
Niels Lohmann et al develop a great JSON parser for C++ called [JSON for Modern
|
||||
C++](https://github.com/nlohmann/json). This validator is based on this
|
||||
library, hence the name.
|
||||
|
||||
The name is for the moment purely marketing, because there is, IMHO, not so much
|
||||
modern C++ inside. There is plenty of space to make it more modern.
|
||||
|
||||
External documentation is missing as well. However the API of the validator
|
||||
will be rather simple.
|
||||
is rather simple.
|
||||
|
||||
# New in version 2
|
||||
|
||||
Although significant changes have been coorporate to the 2 version
|
||||
(a complete rewrite) the API is compatible with the 1.0.0 release. Except for
|
||||
the namespace which is now `nlohmann::json_schema.
|
||||
|
||||
Version **2** supports JSON schema draft 7, whereas 1 was supporting draft 4
|
||||
only. Please update your schemas.
|
||||
|
||||
The primary change in 2 is the way a schema is used. While in version 1 the schema was
|
||||
kept as a JSON-document and used again and again during validation, in versin 2 the schema
|
||||
is parsed into compiled C++ objects which are then used during validation. There are surely
|
||||
still optimizations to be done, but validation speed has improved by factor 100
|
||||
or more.
|
||||
|
||||
In JSON-schema one sub-schema can be
|
||||
|
||||
# Design goals
|
||||
|
||||
The main goal of this validator is to produce *human-comprehensible* error
|
||||
messages if a JSON-document/instance does not comply with its schema. This is
|
||||
done with exceptions thrown at the users with a helpful message telling what's
|
||||
wrong with the document while validating.
|
||||
messages if a JSON-document/instance does not comply to its schema.
|
||||
|
||||
By default this is done with exceptions thrown at the users with a helpful
|
||||
message telling what's wrong with the document while validating.
|
||||
|
||||
With **2.0.0** the user can passed a `json_scheam::basic_error_handler` derived object
|
||||
along with the instance to validate to receive a each time a validation error occurs
|
||||
and decice what to do (throwing, counting, collecting).
|
||||
|
||||
Another goal was to use Niels Lohmann's JSON-library. This is why the validator
|
||||
lives in his namespace.
|
||||
|
||||
# Weaknesses
|
||||
|
||||
Schema-reference resolution is not recursivity-proven: If there is a nested
|
||||
cross-schema reference, it will not stop. (Though I haven't tested it)
|
||||
|
||||
Numerical validation uses `int64_t`, `uint64_t` or `double`, depending on if
|
||||
Numerical validation uses nlohmann integer, unsigned and floating point types, depending on if
|
||||
the schema type is "integer" or "number". Bignum (i.e. arbitrary precision and
|
||||
range) is not supported at this time.
|
||||
|
||||
Unsigned integer validation will only take place if the following two conditions are true:
|
||||
- The nlohmann `type()` of the json object under validation is `nlohmann::json::value_t::number_unsigned`
|
||||
- The schema specifies a numerical minimum greater than or equal to 0
|
||||
Currently JSON-URI with "plain name fragments" are not supported. So referring to an URI
|
||||
with `$ref: "file.json#plain"` will not work.
|
||||
|
||||
# How to use
|
||||
|
||||
The current state of the build-system needs at least version **3.1.1** of NLohmann's
|
||||
The current state of the build-system needs at least version **3.5.0** of NLohmann's
|
||||
JSON library. It is looking for the `json.hpp` within a `nlohmann/`-path.
|
||||
|
||||
When build the library you need to provide the path to the directory where the include-file
|
||||
@ -66,7 +81,7 @@ cmake .. \
|
||||
-DNLOHMANN_JSON_DIR=<path/to/>nlohmann/json.hpp \
|
||||
-DJSON_SCHEMA_TEST_SUITE_PATH=<path/to/JSON-Schema-test-suite> # optional
|
||||
make # install
|
||||
ctest # if test-suite has been given
|
||||
ctest # run unit, non-regression and test-suite tests
|
||||
```
|
||||
### As a subdirectory from within
|
||||
|
||||
@ -93,7 +108,6 @@ In your initial call to cmake simply add:
|
||||
```bash
|
||||
cmake -DBUILD_SHARED_LIBS=ON
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
See also `app/json-schema-validate.cpp`.
|
||||
@ -104,13 +118,12 @@ See also `app/json-schema-validate.cpp`.
|
||||
#include "json-schema.hpp"
|
||||
|
||||
using nlohmann::json;
|
||||
using nlohmann::json_uri;
|
||||
using nlohmann::json_schema_draft4::json_validator;
|
||||
using nlohmann::json_schema::json_validator;
|
||||
|
||||
// The schema is defined based upon a string literal
|
||||
static json person_schema = R"(
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "A person",
|
||||
"properties": {
|
||||
"name": {
|
||||
@ -137,55 +150,74 @@ static json person_schema = R"(
|
||||
static json bad_person = {{"age", 42}};
|
||||
static json good_person = {{"name", "Albert"}, {"age", 42}};
|
||||
|
||||
int main(){
|
||||
int main()
|
||||
{
|
||||
/* json-parse the schema */
|
||||
|
||||
/* json-parse the schema */
|
||||
json_validator validator; // create validator
|
||||
|
||||
json_validator validator; // create validator
|
||||
try {
|
||||
validator.set_root_schema(person_schema); // insert root-schema
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
validator.set_root_schema(person_schema); // insert root-schema
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/* json-parse the people - API of 1.0.0, default throwing error handler */
|
||||
|
||||
/* json-parse the people */
|
||||
for (auto &person : {bad_person, good_person}) {
|
||||
std::cout << "About to validate this person:\n"
|
||||
<< std::setw(2) << person << std::endl;
|
||||
try {
|
||||
validator.validate(person); // validate the document
|
||||
std::cout << "Validation succeeded\n";
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Validation failed, here is why: " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &person : {bad_person, good_person})
|
||||
{
|
||||
std::cout << "About to validate this person:\n" << std::setw(2) << person << std::endl;
|
||||
try {
|
||||
validator.validate(person); // validate the document
|
||||
std::cout << "Validation succeeded\n";
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Validation failed, here is why: " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
/* json-parse the people - with custom error handler */
|
||||
class custom_error_handler : public nlohmann::json_schema::basic_error_handler
|
||||
{
|
||||
void error(const std::string &path, const json &instance, const std::string &message) override
|
||||
{
|
||||
nlohmann::json_schema::basic_error_handler::error(path, instance, message);
|
||||
std::cerr << "ERROR: '" << path << "' - '" << instance << "': " << message << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
for (auto &person : {bad_person, good_person}) {
|
||||
std::cout << "About to validate this person:\n"
|
||||
<< std::setw(2) << person << std::endl;
|
||||
|
||||
custom_error_handler err;
|
||||
validator.validate(person, err); // validate the document - uses the default throwing error-handler
|
||||
|
||||
if (err)
|
||||
std::cerr << "Validation failed\n";
|
||||
else
|
||||
std::cout << "Validation succeeded\n";
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# Compliance
|
||||
|
||||
There is an application which can be used for testing the validator with the
|
||||
[JSON-Schema-Test-Suite](https://github.com/json-schema-org/JSON-Schema-Test-Suite).
|
||||
In order to simplify the testing, the test-suite is included in the repository.
|
||||
|
||||
If you have cloned this repository providing a path the repository-root via the
|
||||
cmake-variable `JSON_SCHEMA_TEST_SUITE_PATH` will enable the test-target(s).
|
||||
|
||||
All required tests are **OK**.
|
||||
|
||||
**12** optional tests of **305** total (required + optional) tests are failing:
|
||||
|
||||
- 10 of them are `format`-strings which are not supported.
|
||||
- big numbers are not working (2)
|
||||
|
||||
# Additional features
|
||||
|
||||
## Default values
|
||||
|
||||
The goal is to create an empty document, based on schema-defined
|
||||
default-values, recursively populated.
|
||||
|
||||
|
||||
@ -1,27 +1,10 @@
|
||||
/*
|
||||
* Modern C++ JSON schema validator
|
||||
* JSON schema validator for JSON for modern C++
|
||||
*
|
||||
* Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
* Copyright (c) 2016-2019 Patrick Boettcher <p@yai.se>.
|
||||
*
|
||||
* Copyright (c) 2016 Patrick Boettcher <patrick.boettcher@posteo.de>.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
||||
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include <json-schema.hpp>
|
||||
|
||||
@ -30,7 +13,7 @@
|
||||
|
||||
using nlohmann::json;
|
||||
using nlohmann::json_uri;
|
||||
using nlohmann::json_schema_draft4::json_validator;
|
||||
using nlohmann::json_schema::json_validator;
|
||||
|
||||
static void usage(const char *name)
|
||||
{
|
||||
@ -47,9 +30,10 @@ static void usage(const char *name)
|
||||
|
||||
static void loader(const json_uri &uri, json &schema)
|
||||
{
|
||||
std::fstream lf("." + uri.path());
|
||||
std::string filename = "./" + uri.path();
|
||||
std::fstream lf(filename);
|
||||
if (!lf.good())
|
||||
throw std::invalid_argument("could not open " + uri.url() + " tried with " + uri.path());
|
||||
throw std::invalid_argument("could not open " + uri.url() + " tried with " + filename);
|
||||
|
||||
try {
|
||||
lf >> schema;
|
||||
@ -58,6 +42,15 @@ static void loader(const json_uri &uri, json &schema)
|
||||
}
|
||||
}
|
||||
|
||||
class custom_error_handler : public nlohmann::json_schema::basic_error_handler
|
||||
{
|
||||
void error(const std::string &path, const json &instance, const std::string &message) override
|
||||
{
|
||||
nlohmann::json_schema::basic_error_handler::error(path, instance, message);
|
||||
std::cerr << "ERROR: '" << path << "' - '" << instance << "': " << message << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 2)
|
||||
@ -95,10 +88,16 @@ int main(int argc, char *argv[])
|
||||
|
||||
try {
|
||||
std::cin >> document;
|
||||
validator.validate(document);
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "json parsing failed: " << e.what() << " at offset: " << std::cin.tellg() << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
custom_error_handler err;
|
||||
validator.validate(document, err);
|
||||
|
||||
if (err) {
|
||||
std::cerr << "schema validation failed\n";
|
||||
std::cerr << e.what() << " at offset: " << std::cin.tellg() << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
90
app/readme.cpp
Normal file
90
app/readme.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "json-schema.hpp"
|
||||
|
||||
using nlohmann::json;
|
||||
using nlohmann::json_schema::json_validator;
|
||||
|
||||
// The schema is defined based upon a string literal
|
||||
static json person_schema = R"(
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "A person",
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Name",
|
||||
"type": "string"
|
||||
},
|
||||
"age": {
|
||||
"description": "Age of the person",
|
||||
"type": "number",
|
||||
"minimum": 2,
|
||||
"maximum": 200
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"name",
|
||||
"age"
|
||||
],
|
||||
"type": "object"
|
||||
}
|
||||
|
||||
)"_json;
|
||||
|
||||
// The people are defined with brace initialization
|
||||
static json bad_person = {{"age", 42}};
|
||||
static json good_person = {{"name", "Albert"}, {"age", 42}};
|
||||
|
||||
int main()
|
||||
{
|
||||
/* json-parse the schema */
|
||||
|
||||
json_validator validator; // create validator
|
||||
|
||||
try {
|
||||
validator.set_root_schema(person_schema); // insert root-schema
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Validation of schema failed, here is why: " << e.what() << "\n";
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* json-parse the people - API of 1.0.0, default throwing error handler */
|
||||
|
||||
for (auto &person : {bad_person, good_person}) {
|
||||
std::cout << "About to validate this person:\n"
|
||||
<< std::setw(2) << person << std::endl;
|
||||
try {
|
||||
validator.validate(person); // validate the document
|
||||
std::cout << "Validation succeeded\n";
|
||||
} catch (const std::exception &e) {
|
||||
std::cerr << "Validation failed, here is why: " << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/* json-parse the people - with custom error handler */
|
||||
class custom_error_handler : public nlohmann::json_schema::basic_error_handler
|
||||
{
|
||||
void error(const std::string &path, const json &instance, const std::string &message) override
|
||||
{
|
||||
nlohmann::json_schema::basic_error_handler::error(path, instance, message);
|
||||
std::cerr << "ERROR: '" << path << "' - '" << instance << "': " << message << "\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
for (auto &person : {bad_person, good_person}) {
|
||||
std::cout << "About to validate this person:\n"
|
||||
<< std::setw(2) << person << std::endl;
|
||||
|
||||
custom_error_handler err;
|
||||
validator.validate(person, err); // validate the document - uses the default throwing error-handler
|
||||
|
||||
if (err)
|
||||
std::cerr << "Validation failed\n";
|
||||
else
|
||||
std::cout << "Validation succeeded\n";
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@ -1,109 +1,114 @@
|
||||
#include <json-schema.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace json_schema_draft4
|
||||
{
|
||||
|
||||
json draft4_schema_builtin = R"( {
|
||||
"id": "http://json-schema.org/draft-04/schema#",
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Core schema meta-schema",
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Core schema meta-schema",
|
||||
"definitions": {
|
||||
"schemaArray": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": { "$ref": "#" }
|
||||
},
|
||||
"positiveInteger": {
|
||||
"nonNegativeInteger": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"positiveIntegerDefault0": {
|
||||
"allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
|
||||
"nonNegativeIntegerDefault0": {
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/nonNegativeInteger" },
|
||||
{ "default": 0 }
|
||||
]
|
||||
},
|
||||
"simpleTypes": {
|
||||
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
|
||||
"enum": [
|
||||
"array",
|
||||
"boolean",
|
||||
"integer",
|
||||
"null",
|
||||
"number",
|
||||
"object",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"stringArray": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"minItems": 1,
|
||||
"uniqueItems": true
|
||||
"uniqueItems": true,
|
||||
"default": []
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"type": ["object", "boolean"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"$id": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
"format": "uri-reference"
|
||||
},
|
||||
"$schema": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"$ref": {
|
||||
"type": "string",
|
||||
"format": "uri-reference"
|
||||
},
|
||||
"$comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": {},
|
||||
"default": true,
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"examples": {
|
||||
"type": "array",
|
||||
"items": true
|
||||
},
|
||||
"multipleOf": {
|
||||
"type": "number",
|
||||
"minimum": 0,
|
||||
"exclusiveMinimum": true
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
"maximum": {
|
||||
"type": "number"
|
||||
},
|
||||
"exclusiveMaximum": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
"type": "number"
|
||||
},
|
||||
"minimum": {
|
||||
"type": "number"
|
||||
},
|
||||
"exclusiveMinimum": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
"type": "number"
|
||||
},
|
||||
"maxLength": { "$ref": "#/definitions/positiveInteger" },
|
||||
"minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
|
||||
"maxLength": { "$ref": "#/definitions/nonNegativeInteger" },
|
||||
"minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
|
||||
"pattern": {
|
||||
"type": "string",
|
||||
"format": "regex"
|
||||
},
|
||||
"additionalItems": {
|
||||
"anyOf": [
|
||||
{ "type": "boolean" },
|
||||
{ "$ref": "#" }
|
||||
],
|
||||
"default": {}
|
||||
},
|
||||
"additionalItems": { "$ref": "#" },
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{ "$ref": "#" },
|
||||
{ "$ref": "#/definitions/schemaArray" }
|
||||
],
|
||||
"default": {}
|
||||
"default": true
|
||||
},
|
||||
"maxItems": { "$ref": "#/definitions/positiveInteger" },
|
||||
"minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
|
||||
"maxItems": { "$ref": "#/definitions/nonNegativeInteger" },
|
||||
"minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
|
||||
"uniqueItems": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"maxProperties": { "$ref": "#/definitions/positiveInteger" },
|
||||
"minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
|
||||
"contains": { "$ref": "#" },
|
||||
"maxProperties": { "$ref": "#/definitions/nonNegativeInteger" },
|
||||
"minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
|
||||
"required": { "$ref": "#/definitions/stringArray" },
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{ "type": "boolean" },
|
||||
{ "$ref": "#" }
|
||||
],
|
||||
"default": {}
|
||||
},
|
||||
"additionalProperties": { "$ref": "#" },
|
||||
"definitions": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "$ref": "#" },
|
||||
@ -117,6 +122,7 @@ json draft4_schema_builtin = R"( {
|
||||
"patternProperties": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "$ref": "#" },
|
||||
"propertyNames": { "format": "regex" },
|
||||
"default": {}
|
||||
},
|
||||
"dependencies": {
|
||||
@ -128,8 +134,11 @@ json draft4_schema_builtin = R"( {
|
||||
]
|
||||
}
|
||||
},
|
||||
"propertyNames": { "$ref": "#" },
|
||||
"const": true,
|
||||
"enum": {
|
||||
"type": "array",
|
||||
"items": true,
|
||||
"minItems": 1,
|
||||
"uniqueItems": true
|
||||
},
|
||||
@ -144,17 +153,16 @@ json draft4_schema_builtin = R"( {
|
||||
}
|
||||
]
|
||||
},
|
||||
"format": { "type": "string" },
|
||||
"contentMediaType": { "type": "string" },
|
||||
"contentEncoding": { "type": "string" },
|
||||
"if": {"$ref": "#"},
|
||||
"then": {"$ref": "#"},
|
||||
"else": {"$ref": "#"},
|
||||
"allOf": { "$ref": "#/definitions/schemaArray" },
|
||||
"anyOf": { "$ref": "#/definitions/schemaArray" },
|
||||
"oneOf": { "$ref": "#/definitions/schemaArray" },
|
||||
"not": { "$ref": "#" }
|
||||
},
|
||||
"dependencies": {
|
||||
"exclusiveMaximum": [ "maximum" ],
|
||||
"exclusiveMinimum": [ "minimum" ]
|
||||
},
|
||||
"default": {}
|
||||
} )"_json;
|
||||
|
||||
}
|
||||
"default": true
|
||||
}
|
||||
185
src/json-schema-draft7.json.cpp
Normal file
185
src/json-schema-draft7.json.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* JSON schema validator for JSON for modern C++
|
||||
*
|
||||
* Copyright (c) 2016-2019 Patrick Boettcher <p@yai.se>.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace json_schema
|
||||
{
|
||||
|
||||
json draft7_schema_builtin = R"( {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "http://json-schema.org/draft-07/schema#",
|
||||
"title": "Core schema meta-schema",
|
||||
"definitions": {
|
||||
"schemaArray": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": { "$ref": "#" }
|
||||
},
|
||||
"nonNegativeInteger": {
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"nonNegativeIntegerDefault0": {
|
||||
"allOf": [
|
||||
{ "$ref": "#/definitions/nonNegativeInteger" },
|
||||
{ "default": 0 }
|
||||
]
|
||||
},
|
||||
"simpleTypes": {
|
||||
"enum": [
|
||||
"array",
|
||||
"boolean",
|
||||
"integer",
|
||||
"null",
|
||||
"number",
|
||||
"object",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"stringArray": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"uniqueItems": true,
|
||||
"default": []
|
||||
}
|
||||
},
|
||||
"type": ["object", "boolean"],
|
||||
"properties": {
|
||||
"$id": {
|
||||
"type": "string",
|
||||
"format": "uri-reference"
|
||||
},
|
||||
"$schema": {
|
||||
"type": "string",
|
||||
"format": "uri"
|
||||
},
|
||||
"$ref": {
|
||||
"type": "string",
|
||||
"format": "uri-reference"
|
||||
},
|
||||
"$comment": {
|
||||
"type": "string"
|
||||
},
|
||||
"title": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"default": true,
|
||||
"readOnly": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"examples": {
|
||||
"type": "array",
|
||||
"items": true
|
||||
},
|
||||
"multipleOf": {
|
||||
"type": "number",
|
||||
"exclusiveMinimum": 0
|
||||
},
|
||||
"maximum": {
|
||||
"type": "number"
|
||||
},
|
||||
"exclusiveMaximum": {
|
||||
"type": "number"
|
||||
},
|
||||
"minimum": {
|
||||
"type": "number"
|
||||
},
|
||||
"exclusiveMinimum": {
|
||||
"type": "number"
|
||||
},
|
||||
"maxLength": { "$ref": "#/definitions/nonNegativeInteger" },
|
||||
"minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
|
||||
"pattern": {
|
||||
"type": "string",
|
||||
"format": "regex"
|
||||
},
|
||||
"additionalItems": { "$ref": "#" },
|
||||
"items": {
|
||||
"anyOf": [
|
||||
{ "$ref": "#" },
|
||||
{ "$ref": "#/definitions/schemaArray" }
|
||||
],
|
||||
"default": true
|
||||
},
|
||||
"maxItems": { "$ref": "#/definitions/nonNegativeInteger" },
|
||||
"minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
|
||||
"uniqueItems": {
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"contains": { "$ref": "#" },
|
||||
"maxProperties": { "$ref": "#/definitions/nonNegativeInteger" },
|
||||
"minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" },
|
||||
"required": { "$ref": "#/definitions/stringArray" },
|
||||
"additionalProperties": { "$ref": "#" },
|
||||
"definitions": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "$ref": "#" },
|
||||
"default": {}
|
||||
},
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "$ref": "#" },
|
||||
"default": {}
|
||||
},
|
||||
"patternProperties": {
|
||||
"type": "object",
|
||||
"additionalProperties": { "$ref": "#" },
|
||||
"propertyNames": { "format": "regex" },
|
||||
"default": {}
|
||||
},
|
||||
"dependencies": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{ "$ref": "#" },
|
||||
{ "$ref": "#/definitions/stringArray" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"propertyNames": { "$ref": "#" },
|
||||
"const": true,
|
||||
"enum": {
|
||||
"type": "array",
|
||||
"items": true,
|
||||
"minItems": 1,
|
||||
"uniqueItems": true
|
||||
},
|
||||
"type": {
|
||||
"anyOf": [
|
||||
{ "$ref": "#/definitions/simpleTypes" },
|
||||
{
|
||||
"type": "array",
|
||||
"items": { "$ref": "#/definitions/simpleTypes" },
|
||||
"minItems": 1,
|
||||
"uniqueItems": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"format": { "type": "string" },
|
||||
"contentMediaType": { "type": "string" },
|
||||
"contentEncoding": { "type": "string" },
|
||||
"if": { "$ref": "#" },
|
||||
"then": { "$ref": "#" },
|
||||
"else": { "$ref": "#" },
|
||||
"allOf": { "$ref": "#/definitions/schemaArray" },
|
||||
"anyOf": { "$ref": "#/definitions/schemaArray" },
|
||||
"oneOf": { "$ref": "#/definitions/schemaArray" },
|
||||
"not": { "$ref": "#" }
|
||||
},
|
||||
"default": true
|
||||
} )"_json;
|
||||
}
|
||||
} // namespace nlohmann
|
||||
@ -1,91 +1,40 @@
|
||||
/*
|
||||
* Modern C++ JSON schema validator
|
||||
* JSON schema validator for JSON for modern C++
|
||||
*
|
||||
* Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
* Copyright (c) 2016-2019 Patrick Boettcher <p@yai.se>.
|
||||
*
|
||||
* Copyright (c) 2016 Patrick Boettcher <patrick.boettcher@posteo.de>.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
||||
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NLOHMANN_JSON_SCHEMA_HPP__
|
||||
#define NLOHMANN_JSON_SCHEMA_HPP__
|
||||
|
||||
#ifdef _WIN32
|
||||
# if defined(JSON_SCHEMA_VALIDATOR_EXPORTS)
|
||||
# define JSON_SCHEMA_VALIDATOR_API __declspec(dllexport)
|
||||
# elif defined(JSON_SCHEMA_VALIDATOR_IMPORTS)
|
||||
# define JSON_SCHEMA_VALIDATOR_API __declspec(dllimport)
|
||||
# else
|
||||
# define JSON_SCHEMA_VALIDATOR_API
|
||||
# endif
|
||||
# if defined(JSON_SCHEMA_VALIDATOR_EXPORTS)
|
||||
# define JSON_SCHEMA_VALIDATOR_API __declspec(dllexport)
|
||||
# elif defined(JSON_SCHEMA_VALIDATOR_IMPORTS)
|
||||
# define JSON_SCHEMA_VALIDATOR_API __declspec(dllimport)
|
||||
# else
|
||||
# define JSON_SCHEMA_VALIDATOR_API
|
||||
# endif
|
||||
#else
|
||||
# define JSON_SCHEMA_VALIDATOR_API
|
||||
# define JSON_SCHEMA_VALIDATOR_API
|
||||
#endif
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#ifdef NLOHMANN_JSON_VERSION_MAJOR
|
||||
# if NLOHMANN_JSON_VERSION_MAJOR < 3 || NLOHMANN_JSON_VERSION_MINOR < 5 || NLOHMANN_JSON_VERSION_PATCH < 0
|
||||
# error "Please use this library with NLohmann's JSON version 3.5.0 or higher"
|
||||
# endif
|
||||
#else
|
||||
# error "expected existing NLOHMANN_JSON_VERSION_MAJOR preproc variable, please update to NLohmann's JSON 3.5.0"
|
||||
#endif
|
||||
|
||||
// make yourself a home - welcome to nlohmann's namespace
|
||||
namespace nlohmann
|
||||
{
|
||||
|
||||
// a class representing a JSON-pointer RFC6901
|
||||
//
|
||||
// examples of JSON pointers
|
||||
//
|
||||
// # - root of the current document
|
||||
// #item - refers to the object which is identified ("id") by `item`
|
||||
// in the current document
|
||||
// #/path/to/element
|
||||
// - refers to the element in /path/to from the root-document
|
||||
//
|
||||
//
|
||||
// The json_pointer-class stores everything in a string, which might seem bizarre
|
||||
// as parsing is done from a string to a string, but from_string() is also
|
||||
// doing some formatting.
|
||||
//
|
||||
// TODO
|
||||
// ~ and % - codec
|
||||
// needs testing and clarification regarding the '#' at the beginning
|
||||
|
||||
class local_json_pointer
|
||||
{
|
||||
std::string str_;
|
||||
|
||||
void from_string(const std::string &r);
|
||||
|
||||
public:
|
||||
local_json_pointer(const std::string &s = "")
|
||||
{
|
||||
from_string(s);
|
||||
}
|
||||
|
||||
void append(const std::string &elem)
|
||||
{
|
||||
str_.append(elem);
|
||||
}
|
||||
|
||||
const std::string &to_string() const
|
||||
{
|
||||
return str_;
|
||||
}
|
||||
};
|
||||
|
||||
// A class representing a JSON-URI for schemas derived from
|
||||
// section 8 of JSON Schema: A Media Type for Describing JSON Documents
|
||||
// draft-wright-json-schema-00
|
||||
@ -102,32 +51,32 @@ class JSON_SCHEMA_VALIDATOR_API json_uri
|
||||
std::string proto_;
|
||||
std::string hostname_;
|
||||
std::string path_;
|
||||
local_json_pointer pointer_;
|
||||
nlohmann::json::json_pointer pointer_;
|
||||
|
||||
protected:
|
||||
// decodes a JSON uri and replaces all or part of the currently stored values
|
||||
void from_string(const std::string &uri);
|
||||
void update(const std::string &uri);
|
||||
|
||||
std::tuple<std::string, std::string, std::string, std::string, std::string> tie() const
|
||||
{
|
||||
return std::tie(urn_, proto_, hostname_, path_, pointer_.to_string());
|
||||
return std::tie(urn_, proto_, hostname_, path_, pointer_);
|
||||
}
|
||||
|
||||
public:
|
||||
json_uri(const std::string &uri)
|
||||
{
|
||||
from_string(uri);
|
||||
update(uri);
|
||||
}
|
||||
|
||||
const std::string protocol() const { return proto_; }
|
||||
const std::string hostname() const { return hostname_; }
|
||||
const std::string path() const { return path_; }
|
||||
const local_json_pointer pointer() const { return pointer_; }
|
||||
|
||||
const std::string url() const;
|
||||
const nlohmann::json::json_pointer pointer() const { return pointer_; }
|
||||
|
||||
const std::string url() const { return location(); }
|
||||
const std::string location() const;
|
||||
|
||||
// decode and encode strings for ~ and % escape sequences
|
||||
static std::string unescape(const std::string &);
|
||||
static std::string escape(const std::string &);
|
||||
|
||||
// create a new json_uri based in this one and the given uri
|
||||
@ -135,7 +84,7 @@ public:
|
||||
json_uri derive(const std::string &uri) const
|
||||
{
|
||||
json_uri u = *this;
|
||||
u.from_string(uri);
|
||||
u.update(uri);
|
||||
return u;
|
||||
}
|
||||
|
||||
@ -143,7 +92,7 @@ public:
|
||||
json_uri append(const std::string &field) const
|
||||
{
|
||||
json_uri u = *this;
|
||||
u.pointer_.append("/" + field);
|
||||
u.pointer_ = nlohmann::json::json_pointer(u.pointer_.to_string() + '/' + escape(field));
|
||||
return u;
|
||||
}
|
||||
|
||||
@ -162,42 +111,47 @@ public:
|
||||
friend std::ostream &operator<<(std::ostream &os, const json_uri &u);
|
||||
};
|
||||
|
||||
namespace json_schema_draft4
|
||||
namespace json_schema
|
||||
{
|
||||
|
||||
extern json draft4_schema_builtin;
|
||||
extern json draft7_schema_builtin;
|
||||
|
||||
class basic_error_handler
|
||||
{
|
||||
bool error_{false};
|
||||
|
||||
public:
|
||||
virtual void error(const std::string & /*path*/, const json & /* instance */, const std::string & /*message*/)
|
||||
{
|
||||
error_ = true;
|
||||
}
|
||||
|
||||
void reset() { error_ = false; }
|
||||
operator bool() const { return error_; }
|
||||
};
|
||||
|
||||
class root_schema;
|
||||
|
||||
class JSON_SCHEMA_VALIDATOR_API json_validator
|
||||
{
|
||||
std::vector<std::shared_ptr<json>> schema_store_;
|
||||
std::shared_ptr<json> root_schema_;
|
||||
std::function<void(const json_uri &, json &)> schema_loader_ = nullptr;
|
||||
std::function<void(const std::string &, const std::string &)> format_check_ = nullptr;
|
||||
|
||||
std::map<json_uri, const json *> schema_refs_;
|
||||
|
||||
void validate(const json &instance, const json &schema_, const std::string &name);
|
||||
void validate_array(const json &instance, const json &schema_, const std::string &name);
|
||||
void validate_object(const json &instance, const json &schema_, const std::string &name);
|
||||
void validate_string(const json &instance, const json &schema, const std::string &name);
|
||||
|
||||
void insert_schema(const json &input, const json_uri &id);
|
||||
std::unique_ptr<root_schema> root_;
|
||||
|
||||
public:
|
||||
json_validator(std::function<void(const json_uri &, json &)> loader = nullptr,
|
||||
std::function<void(const std::string &, const std::string &)> format = nullptr)
|
||||
: schema_loader_(loader), format_check_(format)
|
||||
{
|
||||
}
|
||||
std::function<void(const std::string &, const std::string &)> format = nullptr);
|
||||
~json_validator();
|
||||
|
||||
// insert and set a root-schema
|
||||
// insert and set thea root-schema
|
||||
void set_root_schema(const json &);
|
||||
|
||||
// validate a json-document based on the root-schema
|
||||
void validate(const json &instance);
|
||||
void validate(const json &);
|
||||
|
||||
// validate a json-document based on the root-schema with a custom error-handler
|
||||
void validate(const json &, basic_error_handler &);
|
||||
};
|
||||
|
||||
} // json_schema_draft4
|
||||
} // nlohmann
|
||||
} // namespace json_schema
|
||||
} // namespace nlohmann
|
||||
|
||||
#endif /* NLOHMANN_JSON_SCHEMA_HPP__ */
|
||||
|
||||
198
src/json-uri.cpp
198
src/json-uri.cpp
@ -1,27 +1,10 @@
|
||||
/*
|
||||
* Modern C++ JSON schema validator
|
||||
* JSON schema validator for JSON for modern C++
|
||||
*
|
||||
* Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
* Copyright (c) 2016-2019 Patrick Boettcher <p@yai.se>.
|
||||
*
|
||||
* Copyright (c) 2016 Patrick Boettcher <patrick.boettcher@posteo.de>.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
||||
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "json-schema.hpp"
|
||||
|
||||
@ -30,76 +13,92 @@
|
||||
namespace nlohmann
|
||||
{
|
||||
|
||||
void local_json_pointer::from_string(const std::string &r)
|
||||
void json_uri::update(const std::string &uri)
|
||||
{
|
||||
str_ = "#";
|
||||
std::string pointer = ""; // default pointer is document-root
|
||||
|
||||
if (r.size() == 0)
|
||||
return;
|
||||
|
||||
if (r[0] != '#')
|
||||
throw std::invalid_argument("not a valid JSON pointer - missing # at the beginning");
|
||||
|
||||
if (r.size() == 1)
|
||||
return;
|
||||
|
||||
std::size_t pos = 1;
|
||||
|
||||
do {
|
||||
std::size_t next = r.find('/', pos + 1);
|
||||
str_.append(r.substr(pos, next - pos));
|
||||
pos = next;
|
||||
} while (pos != std::string::npos);
|
||||
}
|
||||
|
||||
void json_uri::from_string(const std::string &uri)
|
||||
{
|
||||
// if it is an urn take it as it is - maybe there is more to be done
|
||||
if (uri.find("urn:") == 0) {
|
||||
urn_ = uri;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string pointer = "#"; // default pointer is the root
|
||||
|
||||
// first split the URI into URL and JSON-pointer
|
||||
// first split the URI into location and pointer
|
||||
auto pointer_separator = uri.find('#');
|
||||
if (pointer_separator != std::string::npos) // and extract the JSON-pointer-string if found
|
||||
pointer = uri.substr(pointer_separator);
|
||||
if (pointer_separator != std::string::npos) { // and extract the pointer-string if found
|
||||
pointer = uri.substr(pointer_separator + 1); // remove #
|
||||
|
||||
// the rest is an URL
|
||||
std::string url = uri.substr(0, pointer_separator);
|
||||
if (url.size()) { // if an URL is part of the URI
|
||||
// unescape %-values IOW, decode JSON-URI-formatted JSON-pointer
|
||||
std::size_t pos = pointer.size() - 1;
|
||||
do {
|
||||
pos = pointer.rfind('%', pos);
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
|
||||
std::size_t pos = 0;
|
||||
auto proto = url.find("://", pos);
|
||||
if (proto != std::string::npos) { // extract the protocol
|
||||
proto_ = url.substr(pos, proto - pos);
|
||||
pos = 3 + proto; // 3 == "://"
|
||||
|
||||
auto hostname = url.find("/", pos);
|
||||
if (hostname != std::string::npos) { // and the hostname (no proto without hostname)
|
||||
hostname_ = url.substr(pos, hostname - pos);
|
||||
pos = hostname;
|
||||
if (pos >= pointer.size() - 2) {
|
||||
pos--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// the rest is the path
|
||||
auto path = url.substr(pos);
|
||||
if (path[0] == '/') // if it starts with a / it is root-path
|
||||
path_ = path;
|
||||
else // otherwise it is a subfolder
|
||||
path_.append(path);
|
||||
std::string hex = pointer.substr(pos + 1, 2);
|
||||
char ascii = (char) std::strtoul(hex.c_str(), nullptr, 16);
|
||||
pointer.replace(pos, 3, 1, ascii);
|
||||
|
||||
pointer_ = local_json_pointer("");
|
||||
pos--;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
if (pointer.size() > 0)
|
||||
pointer_ = pointer;
|
||||
auto location = uri.substr(0, pointer_separator);
|
||||
|
||||
if (location.size()) { // a location part has been found
|
||||
pointer_ = ""_json_pointer; // if a location is given, the pointer is emptied
|
||||
|
||||
// if it is an URN take it as it is
|
||||
if (location.find("urn:") == 0) {
|
||||
urn_ = location;
|
||||
|
||||
// and clear URL members
|
||||
proto_ = "";
|
||||
hostname_ = "";
|
||||
path_ = "";
|
||||
|
||||
} else { // it is an URL
|
||||
|
||||
// split URL in protocol, hostname and path
|
||||
std::size_t pos = 0;
|
||||
auto proto = location.find("://", pos);
|
||||
if (proto != std::string::npos) { // extract the protocol
|
||||
|
||||
urn_ = ""; // clear URN-member if URL is parsed
|
||||
|
||||
proto_ = location.substr(pos, proto - pos);
|
||||
pos = 3 + proto; // 3 == "://"
|
||||
|
||||
auto hostname = location.find("/", pos);
|
||||
if (hostname != std::string::npos) { // and the hostname (no proto without hostname)
|
||||
hostname_ = location.substr(pos, hostname - pos);
|
||||
pos = hostname;
|
||||
}
|
||||
}
|
||||
|
||||
auto path = location.substr(pos);
|
||||
|
||||
// URNs cannot of have paths
|
||||
if (urn_.size() && path.size())
|
||||
throw std::invalid_argument("Cannot add a path (" + path + ") to an URN URI (" + urn_ + ")");
|
||||
|
||||
if (path[0] == '/') // if it starts with a / it is root-path
|
||||
path_ = path;
|
||||
else if (pos == 0) { // the URL contained only a path and the current path has no / at the end, strip last element until / and append
|
||||
auto last_slash = path_.rfind('/');
|
||||
path_ = path_.substr(0, last_slash) + '/' + path;
|
||||
} else // otherwise it is a subfolder
|
||||
path_.append(path);
|
||||
}
|
||||
}
|
||||
|
||||
pointer_ = nlohmann::json::json_pointer(pointer);
|
||||
}
|
||||
|
||||
const std::string json_uri::url() const
|
||||
const std::string json_uri::location() const
|
||||
{
|
||||
if (urn_.size())
|
||||
return urn_;
|
||||
|
||||
std::stringstream s;
|
||||
|
||||
if (proto_.size() > 0)
|
||||
@ -115,9 +114,7 @@ std::string json_uri::to_string() const
|
||||
{
|
||||
std::stringstream s;
|
||||
|
||||
s << urn_
|
||||
<< url()
|
||||
<< pointer_.to_string();
|
||||
s << location() << " # " << pointer_.to_string();
|
||||
|
||||
return s.str();
|
||||
}
|
||||
@ -127,48 +124,11 @@ std::ostream &operator<<(std::ostream &os, const json_uri &u)
|
||||
return os << u.to_string();
|
||||
}
|
||||
|
||||
std::string json_uri::unescape(const std::string &src)
|
||||
{
|
||||
std::string l = src;
|
||||
std::size_t pos = src.size() - 1;
|
||||
|
||||
do {
|
||||
pos = l.rfind('~', pos);
|
||||
|
||||
if (pos == std::string::npos)
|
||||
break;
|
||||
|
||||
if (pos < l.size() - 1) {
|
||||
switch (l[pos + 1]) {
|
||||
case '0':
|
||||
l.replace(pos, 2, "~");
|
||||
break;
|
||||
|
||||
case '1':
|
||||
l.replace(pos, 2, "/");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos == 0)
|
||||
break;
|
||||
pos--;
|
||||
} while (pos != std::string::npos);
|
||||
|
||||
// TODO - percent handling
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
std::string json_uri::escape(const std::string &src)
|
||||
{
|
||||
std::vector<std::pair<std::string, std::string>> chars = {
|
||||
{"~", "~0"},
|
||||
{"/", "~1"},
|
||||
{"%", "%25"}};
|
||||
{"/", "~1"}};
|
||||
|
||||
std::string l = src;
|
||||
|
||||
@ -186,4 +146,4 @@ std::string json_uri::escape(const std::string &src)
|
||||
return l;
|
||||
}
|
||||
|
||||
} // nlohmann
|
||||
} // namespace nlohmann
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,8 @@ function(add_test_simple_schema name schema instance)
|
||||
COMMAND ${PIPE_IN_TEST_SCRIPT}
|
||||
$<TARGET_FILE:json-schema-validate>
|
||||
${schema}
|
||||
${instance})
|
||||
${instance}
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endfunction()
|
||||
|
||||
file(GLOB TEST_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/*)
|
||||
@ -17,3 +18,8 @@ foreach(DIR ${TEST_DIRS})
|
||||
add_subdirectory(${DIR})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
add_executable(uri uri.cpp)
|
||||
target_link_libraries(uri json-schema-validator)
|
||||
|
||||
add_test(NAME uri COMMAND uri)
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
set(JSON_SCHEMA_TEST_PREFIX "JSON-Suite" CACHE STRING "prefix for JSON-tests added to ctest")
|
||||
|
||||
set(DRAFT "draft7")
|
||||
|
||||
# find schema-test-suite
|
||||
find_path(JSON_SCHEMA_TEST_SUITE_PATH
|
||||
NAMES
|
||||
tests/draft4)
|
||||
tests/${DRAFT})
|
||||
|
||||
if (NOT JSON_SCHEMA_TEST_SUITE_PATH)
|
||||
message(STATUS "Set JSON_SCHEMA_TEST_SUITE_PATH to a path in which JSON-Schema-Test-Suite is located (github.com/json-schema-org/JSON-Schema-Test-Suite). Using internal test-suite which might be out of date.")
|
||||
@ -21,7 +23,7 @@ if(JSON_SCHEMA_TEST_SUITE_PATH)
|
||||
option(JSON_SCHEMA_ENABLE_OPTIONAL_TESTS "Enable optional tests of the JSONSchema Test Suite" ON)
|
||||
|
||||
# create tests foreach test-file
|
||||
file(GLOB TEST_FILES ${JSON_SCHEMA_TEST_SUITE_PATH}/tests/draft4/*.json)
|
||||
file(GLOB TEST_FILES ${JSON_SCHEMA_TEST_SUITE_PATH}/tests/${DRAFT}/*.json)
|
||||
|
||||
foreach(TEST_FILE ${TEST_FILES})
|
||||
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
|
||||
@ -30,7 +32,7 @@ if(JSON_SCHEMA_TEST_SUITE_PATH)
|
||||
endforeach()
|
||||
|
||||
if (JSON_SCHEMA_ENABLE_OPTIONAL_TESTS)
|
||||
file(GLOB OPT_TEST_FILES ${JSON_SCHEMA_TEST_SUITE_PATH}/tests/draft4/optional/*.json)
|
||||
file(GLOB OPT_TEST_FILES ${JSON_SCHEMA_TEST_SUITE_PATH}/tests/${DRAFT}/optional/*.json)
|
||||
|
||||
foreach(TEST_FILE ${OPT_TEST_FILES})
|
||||
get_filename_component(TEST_NAME ${TEST_FILE} NAME_WE)
|
||||
@ -38,18 +40,13 @@ if(JSON_SCHEMA_TEST_SUITE_PATH)
|
||||
COMMAND ${PIPE_IN_TEST_SCRIPT} $<TARGET_FILE:json-schema-test> ${TEST_FILE})
|
||||
endforeach()
|
||||
|
||||
# XXX Unfortunately URLs are not very well handled yet, accept those tests which fail
|
||||
set_tests_properties(JSON-Suite::ref
|
||||
JSON-Suite::refRemote
|
||||
PROPERTIES
|
||||
WILL_FAIL ON)
|
||||
|
||||
# some optional tests will fail as well.
|
||||
set_tests_properties(JSON-Suite::Optional::bignum
|
||||
JSON-Suite::Optional::ecmascript-regex
|
||||
JSON-Suite::Optional::format
|
||||
PROPERTIES
|
||||
WILL_FAIL ON)
|
||||
set_tests_properties(
|
||||
JSON-Suite::Optional::bignum
|
||||
JSON-Suite::Optional::content
|
||||
JSON-Suite::Optional::zeroTerminatedFloats
|
||||
PROPERTIES
|
||||
WILL_FAIL ON)
|
||||
endif()
|
||||
else()
|
||||
endif()
|
||||
|
||||
@ -1,37 +1,20 @@
|
||||
/*
|
||||
* Modern C++ JSON schema validator
|
||||
* JSON schema validator for JSON for modern C++
|
||||
*
|
||||
* Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
* Copyright (c) 2016-2019 Patrick Boettcher <p@yai.se>.
|
||||
*
|
||||
* Copyright (c) 2016 Patrick Boettcher <patrick.boettcher@posteo.de>.
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom
|
||||
* the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
* NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
|
||||
* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
||||
* THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "json-schema.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <iostream>
|
||||
#include <regex>
|
||||
|
||||
using nlohmann::json;
|
||||
using nlohmann::json_uri;
|
||||
using nlohmann::json_schema_draft4::json_validator;
|
||||
using nlohmann::json_schema::json_validator;
|
||||
|
||||
static void format_check(const std::string &format, const std::string &value)
|
||||
{
|
||||
@ -61,8 +44,8 @@ static void format_check(const std::string &format, const std::string &value)
|
||||
|
||||
static void loader(const json_uri &uri, json &schema)
|
||||
{
|
||||
if (uri.to_string() == "http://json-schema.org/draft-04/schema#") {
|
||||
schema = nlohmann::json_schema_draft4::draft4_schema_builtin;
|
||||
if (uri.location() == "http://json-schema.org/draft-07/schema") {
|
||||
schema = nlohmann::json_schema::draft7_schema_builtin;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "integer"
|
||||
}
|
||||
3
test/JSON-Schema-Test-Suite/remotes/integer.json
Normal file
3
test/JSON-Schema-Test-Suite/remotes/integer.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "integer"
|
||||
}
|
||||
11
test/JSON-Schema-Test-Suite/remotes/name.json
Normal file
11
test/JSON-Schema-Test-Suite/remotes/name.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"definitions": {
|
||||
"orNull": {
|
||||
"anyOf": [
|
||||
{"type": "null"},
|
||||
{"$ref": "#"}
|
||||
]
|
||||
}
|
||||
},
|
||||
"type": "string"
|
||||
}
|
||||
8
test/JSON-Schema-Test-Suite/remotes/subSchemas.json
Normal file
8
test/JSON-Schema-Test-Suite/remotes/subSchemas.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"integer": {
|
||||
"type": "integer"
|
||||
},
|
||||
"refToInteger": {
|
||||
"$ref": "#/integer"
|
||||
}
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
[
|
||||
{
|
||||
"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 (explicit false exclusivity)",
|
||||
"schema": {"maximum": 3.0, "exclusiveMaximum": false},
|
||||
"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": "exclusiveMaximum validation",
|
||||
"schema": {
|
||||
"maximum": 3.0,
|
||||
"exclusiveMaximum": true
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "below the maximum is still valid",
|
||||
"data": 2.2,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "boundary point is invalid",
|
||||
"data": 3.0,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -1,73 +0,0 @@
|
||||
[
|
||||
{
|
||||
"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 (explicit false exclusivity)",
|
||||
"schema": {"minimum": 1.1, "exclusiveMinimum": false},
|
||||
"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": "exclusiveMinimum validation",
|
||||
"schema": {
|
||||
"minimum": 1.1,
|
||||
"exclusiveMinimum": true
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "above the minimum is still valid",
|
||||
"data": 1.2,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "boundary point is invalid",
|
||||
"data": 1.1,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -1,223 +0,0 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of date-time strings",
|
||||
"schema": {"format": "date-time"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid date-time string",
|
||||
"data": "1963-06-19T08:30:06.283185Z",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an invalid date-time string",
|
||||
"data": "06/19/1963 08:30:06 PST",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "only RFC3339 not all of ISO 8601 are valid",
|
||||
"data": "2013-350T01:01:01",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "validation of URIs",
|
||||
"schema": {"format": "uri"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid URL with anchor tag",
|
||||
"data": "http://foo.bar/?baz=qux#quux",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a valid URL with anchor tag and parantheses",
|
||||
"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": "validation of e-mail addresses",
|
||||
"schema": {"format": "email"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid e-mail address",
|
||||
"data": "joe.bloggs@example.com",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an invalid e-mail address",
|
||||
"data": "2962",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "validation of IP addresses",
|
||||
"schema": {"format": "ipv4"},
|
||||
"tests": [
|
||||
{
|
||||
"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": "validation of IPv6 addresses",
|
||||
"schema": {"format": "ipv6"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid IPv6 address",
|
||||
"data": "::1",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an IPv6 address with out-of-range values",
|
||||
"data": "12345::",
|
||||
"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": "validation of host names",
|
||||
"schema": {"format": "hostname"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid host name",
|
||||
"data": "www.example.com",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -40,6 +40,25 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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 allows a schema which should validate",
|
||||
@ -94,5 +113,21 @@
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "additionalProperties should not look in applicators",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{"properties": {"foo": {}}}
|
||||
],
|
||||
"additionalProperties": {"type": "boolean"}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "properties defined in allOf are not allowed",
|
||||
"data": {"foo": 1, "bar": true},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -108,5 +108,38 @@
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -65,6 +65,39 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": {
|
||||
104
test/JSON-Schema-Test-Suite/tests/draft7/boolean_schema.json
Normal file
104
test/JSON-Schema-Test-Suite/tests/draft7/boolean_schema.json
Normal file
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
86
test/JSON-Schema-Test-Suite/tests/draft7/const.json
Normal file
86
test/JSON-Schema-Test-Suite/tests/draft7/const.json
Normal file
@ -0,0 +1,86 @@
|
||||
[
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
95
test/JSON-Schema-Test-Suite/tests/draft7/contains.json
Normal file
95
test/JSON-Schema-Test-Suite/tests/draft7/contains.json
Normal file
@ -0,0 +1,95 @@
|
||||
[
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -1,7 +1,7 @@
|
||||
[
|
||||
{
|
||||
"description": "valid definition",
|
||||
"schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
|
||||
"schema": {"$ref": "http://json-schema.org/draft-07/schema#"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "valid definition schema",
|
||||
@ -16,7 +16,7 @@
|
||||
},
|
||||
{
|
||||
"description": "invalid definition",
|
||||
"schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
|
||||
"schema": {"$ref": "http://json-schema.org/draft-07/schema#"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "invalid definition schema",
|
||||
@ -42,6 +42,24 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": "multiple dependencies",
|
||||
"schema": {
|
||||
@ -119,5 +137,36 @@
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -39,13 +39,13 @@
|
||||
{
|
||||
"description": "enums in properties",
|
||||
"schema": {
|
||||
"type":"object",
|
||||
"properties": {
|
||||
"foo": {"enum":["foo"]},
|
||||
"bar": {"enum":["bar"]}
|
||||
},
|
||||
"required": ["bar"]
|
||||
},
|
||||
"type":"object",
|
||||
"properties": {
|
||||
"foo": {"enum":["foo"]},
|
||||
"bar": {"enum":["bar"]}
|
||||
},
|
||||
"required": ["bar"]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "both properties are valid",
|
||||
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
188
test/JSON-Schema-Test-Suite/tests/draft7/if-then-else.json
Normal file
188
test/JSON-Schema-Test-Suite/tests/draft7/if-then-else.json
Normal file
@ -0,0 +1,188 @@
|
||||
[
|
||||
{
|
||||
"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 woud have been invalid through then",
|
||||
"data": -100,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "valid, but would have been invalid through else",
|
||||
"data": 3,
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -74,5 +74,60 @@
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
28
test/JSON-Schema-Test-Suite/tests/draft7/maximum.json
Normal file
28
test/JSON-Schema-Test-Suite/tests/draft7/maximum.json
Normal file
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
28
test/JSON-Schema-Test-Suite/tests/draft7/minimum.json
Normal file
28
test/JSON-Schema-Test-Suite/tests/draft7/minimum.json
Normal file
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -91,6 +91,27 @@
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
||||
@ -65,6 +65,50 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": {
|
||||
@ -68,8 +68,7 @@
|
||||
{
|
||||
"description": "float comparison with high precision",
|
||||
"schema": {
|
||||
"maximum": 972783798187987123879878123.18878137,
|
||||
"exclusiveMaximum": true
|
||||
"exclusiveMaximum": 972783798187987123879878123.18878137
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
@ -93,8 +92,7 @@
|
||||
{
|
||||
"description": "float comparison with high precision on negative numbers",
|
||||
"schema": {
|
||||
"minimum": -972783798187987123879878123.18878137,
|
||||
"exclusiveMinimum": true
|
||||
"exclusiveMinimum": -972783798187987123879878123.18878137
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,53 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of date-time strings",
|
||||
"schema": {"format": "date-time"},
|
||||
"tests": [
|
||||
{
|
||||
"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 invalid day in date-time string",
|
||||
"data": "1990-02-31T15:59:60.123-08:00",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an invalid offset in date-time string",
|
||||
"data": "1990-12-31T15:59:60-24:00",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of date strings",
|
||||
"schema": {"format": "date"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid date string",
|
||||
"data": "1963-06-19",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an invalid date-time string",
|
||||
"data": "06/19/1963",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "only RFC3339 not all of ISO 8601 are valid",
|
||||
"data": "2013-350",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of e-mail addresses",
|
||||
"schema": {"format": "email"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid e-mail address",
|
||||
"data": "joe.bloggs@example.com",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an invalid e-mail address",
|
||||
"data": "2962",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,33 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of host names",
|
||||
"schema": {"format": "hostname"},
|
||||
"tests": [
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of an internationalized e-mail addresses",
|
||||
"schema": {"format": "idn-email"},
|
||||
"tests": [
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of internationalized host names",
|
||||
"schema": {"format": "idn-hostname"},
|
||||
"tests": [
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,33 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of IP addresses",
|
||||
"schema": {"format": "ipv4"},
|
||||
"tests": [
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of IPv6 addresses",
|
||||
"schema": {"format": "ipv6"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid IPv6 address",
|
||||
"data": "::1",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an IPv6 address with out-of-range values",
|
||||
"data": "12345::",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,43 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of IRI References",
|
||||
"schema": {"format": "iri-reference"},
|
||||
"tests": [
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,53 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of IRIs",
|
||||
"schema": {"format": "iri"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid IRI with anchor tag",
|
||||
"data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a valid IRI with anchor tag and parantheses",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,168 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of JSON-pointers (JSON String Representation)",
|
||||
"schema": {"format": "json-pointer"},
|
||||
"tests": [
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of regular expressions",
|
||||
"schema": {"format": "regex"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid regular expression",
|
||||
"data": "([abc])+\\s+$",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a regular expression with unclosed parens is invalid",
|
||||
"data": "^(abc]",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,33 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of Relative JSON Pointers (RJP)",
|
||||
"schema": {"format": "relative-json-pointer"},
|
||||
"tests": [
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of time strings",
|
||||
"schema": {"format": "time"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid time string",
|
||||
"data": "08:30:06.283185Z",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an invalid time string",
|
||||
"data": "08:30:06 PST",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "only RFC3339 not all of ISO 8601 are valid",
|
||||
"data": "01:01:01,1111",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,43 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of URI References",
|
||||
"schema": {"format": "uri-reference"},
|
||||
"tests": [
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,30 @@
|
||||
[
|
||||
{
|
||||
"description": "format: uri-template",
|
||||
"schema": {
|
||||
"format": "uri-template"
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,103 @@
|
||||
[
|
||||
{
|
||||
"description": "validation of URIs",
|
||||
"schema": {"format": "uri"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a valid URL with anchor tag",
|
||||
"data": "http://foo.bar/?baz=qux#quux",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a valid URL with anchor tag and parantheses",
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -6,9 +6,9 @@
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a float is not an integer even without fractional part",
|
||||
"description": "a float without fractional part is an integer",
|
||||
"data": 1.0,
|
||||
"valid": false
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -30,12 +30,12 @@
|
||||
},
|
||||
{
|
||||
"description": "ignores arrays",
|
||||
"data": [],
|
||||
"data": ["foo"],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ignores strings",
|
||||
"data": "",
|
||||
"data": "foo",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
@ -116,5 +116,36 @@
|
||||
"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": "empty object is valid",
|
||||
"data": {},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -93,5 +93,36 @@
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
78
test/JSON-Schema-Test-Suite/tests/draft7/propertyNames.json
Normal file
78
test/JSON-Schema-Test-Suite/tests/draft7/propertyNames.json
Normal file
@ -0,0 +1,78 @@
|
||||
[
|
||||
{
|
||||
"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 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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -175,7 +175,7 @@
|
||||
},
|
||||
{
|
||||
"description": "remote ref, containing refs itself",
|
||||
"schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
|
||||
"schema": {"$ref": "http://json-schema.org/draft-07/schema#"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "remote ref valid",
|
||||
@ -209,10 +209,42 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ref to boolean schema true",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/bool",
|
||||
"definitions": {
|
||||
"bool": true
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "any value is valid",
|
||||
"data": "foo",
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "$ref to boolean schema false",
|
||||
"schema": {
|
||||
"$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",
|
||||
"$id": "http://localhost:1234/tree",
|
||||
"description": "tree of nodes",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -225,7 +257,7 @@
|
||||
"required": ["meta", "nodes"],
|
||||
"definitions": {
|
||||
"node": {
|
||||
"id": "http://localhost:1234/node",
|
||||
"$id": "http://localhost:1234/node",
|
||||
"description": "node",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@ -239,7 +271,7 @@
|
||||
"tests": [
|
||||
{
|
||||
"description": "valid tree",
|
||||
"data": {
|
||||
"data": {
|
||||
"meta": "root",
|
||||
"nodes": [
|
||||
{
|
||||
@ -268,7 +300,7 @@
|
||||
},
|
||||
{
|
||||
"description": "invalid tree",
|
||||
"data": {
|
||||
"data": {
|
||||
"meta": "root",
|
||||
"nodes": [
|
||||
{
|
||||
@ -52,9 +52,9 @@
|
||||
{
|
||||
"description": "base URI change",
|
||||
"schema": {
|
||||
"id": "http://localhost:1234/",
|
||||
"$id": "http://localhost:1234/",
|
||||
"items": {
|
||||
"id": "folder/",
|
||||
"$id": "folder/",
|
||||
"items": {"$ref": "folderInteger.json"}
|
||||
}
|
||||
},
|
||||
@ -74,14 +74,14 @@
|
||||
{
|
||||
"description": "base URI change - change folder",
|
||||
"schema": {
|
||||
"id": "http://localhost:1234/scope_change_defs1.json",
|
||||
"$id": "http://localhost:1234/scope_change_defs1.json",
|
||||
"type" : "object",
|
||||
"properties": {
|
||||
"list": {"$ref": "#/definitions/baz"}
|
||||
},
|
||||
"definitions": {
|
||||
"baz": {
|
||||
"id": "folder/",
|
||||
"$id": "folder/",
|
||||
"type": "array",
|
||||
"items": {"$ref": "folderInteger.json"}
|
||||
}
|
||||
@ -103,14 +103,14 @@
|
||||
{
|
||||
"description": "base URI change - change folder in subschema",
|
||||
"schema": {
|
||||
"id": "http://localhost:1234/scope_change_defs2.json",
|
||||
"$id": "http://localhost:1234/scope_change_defs2.json",
|
||||
"type" : "object",
|
||||
"properties": {
|
||||
"list": {"$ref": "#/definitions/baz/definitions/bar"}
|
||||
},
|
||||
"definitions": {
|
||||
"baz": {
|
||||
"id": "folder/",
|
||||
"$id": "folder/",
|
||||
"definitions": {
|
||||
"bar": {
|
||||
"type": "array",
|
||||
@ -136,7 +136,7 @@
|
||||
{
|
||||
"description": "root ref in remote ref",
|
||||
"schema": {
|
||||
"id": "http://localhost:1234/object",
|
||||
"$id": "http://localhost:1234/object",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"$ref": "name.json#/definitions/orNull"}
|
||||
@ -50,5 +50,21 @@
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "required with empty array",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {}
|
||||
},
|
||||
"required": []
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "property not required",
|
||||
"data": {},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
146
test/id-ref.cpp
Normal file
146
test/id-ref.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "../src/json-schema.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
auto schema_draft = R"(
|
||||
{
|
||||
"$id": "http://example.com/root.json",
|
||||
"definitions": {
|
||||
"A": { "$id": "#foo" },
|
||||
"B": {
|
||||
"$id": "other.json",
|
||||
"definitions": {
|
||||
"X": { "$id": "#bar" },
|
||||
"Y": { "$id": "t/inner.json" }
|
||||
}
|
||||
},
|
||||
"C": {
|
||||
|
||||
"$id": "urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f",
|
||||
"definitions": {
|
||||
"Z": { "$id": "#bar" },
|
||||
"9": { "$id": "http://example.com/drole.json" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)"_json;
|
||||
|
||||
/* # (document root)
|
||||
|
||||
http://example.com/root.json
|
||||
http://example.com/root.json#
|
||||
|
||||
#/definitions/A
|
||||
|
||||
http://example.com/root.json#foo
|
||||
http://example.com/root.json#/definitions/A
|
||||
|
||||
#/definitions/B
|
||||
|
||||
http://example.com/other.json
|
||||
http://example.com/other.json#
|
||||
http://example.com/root.json#/definitions/B
|
||||
|
||||
#/definitions/B/definitions/X
|
||||
|
||||
http://example.com/other.json#bar
|
||||
http://example.com/other.json#/definitions/X
|
||||
http://example.com/root.json#/definitions/B/definitions/X
|
||||
|
||||
#/definitions/B/definitions/Y
|
||||
|
||||
http://example.com/t/inner.json
|
||||
http://example.com/t/inner.json#
|
||||
http://example.com/other.json#/definitions/Y
|
||||
http://example.com/root.json#/definitions/B/definitions/Y
|
||||
|
||||
#/definitions/C
|
||||
|
||||
urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f
|
||||
urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f#
|
||||
http://example.com/root.json#/definitions/C
|
||||
*/
|
||||
|
||||
auto schema = R"(
|
||||
{
|
||||
"id": "http://localhost:1234/scope_change_defs2.json",
|
||||
"type" : "object",
|
||||
"properties": {
|
||||
"list": {"$ref": "#/definitions/baz/definitions/bar"}
|
||||
},
|
||||
"definitions": {
|
||||
"baz": {
|
||||
"id": "folder/",
|
||||
"definitions": {
|
||||
"bar": {
|
||||
"type": "array",
|
||||
"items": {"$ref": "folderInteger.json"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})"_json;
|
||||
|
||||
class json_schema_validator
|
||||
{
|
||||
public:
|
||||
std::vector<json> schemas_;
|
||||
std::map<nlohmann::json_uri, const json *> schema_store_;
|
||||
|
||||
public:
|
||||
void insert_schema(json &s, std::vector<nlohmann::json_uri> base_uris)
|
||||
{
|
||||
auto id = s.find("$id");
|
||||
if (id != s.end())
|
||||
base_uris.push_back(base_uris.back().derive(id.value()));
|
||||
|
||||
for (auto &u : base_uris)
|
||||
schema_store_[u] = &s;
|
||||
|
||||
for (auto i = s.begin();
|
||||
i != s.end();
|
||||
++i) {
|
||||
|
||||
switch (i.value().type()) {
|
||||
case json::value_t::object: { // child is object, thus a schema
|
||||
std::vector<nlohmann::json_uri> subschema_uri = base_uris;
|
||||
|
||||
for (auto &ss : subschema_uri)
|
||||
ss = ss.append(nlohmann::json_uri::escape(i.key()));
|
||||
|
||||
insert_schema(i.value(), subschema_uri);
|
||||
} break;
|
||||
|
||||
case json::value_t::string:
|
||||
// this schema is a reference
|
||||
if (i.key() == "$ref") {
|
||||
auto id = base_uris.back().derive(i.value());
|
||||
i.value() = id.to_string();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
json_schema_validator store;
|
||||
|
||||
store.insert_schema(schema_draft, {{"#"}});
|
||||
|
||||
for (auto &i : store.schema_store_) {
|
||||
std::cerr << i.first << " " << *i.second << "\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
{
|
||||
"id": "http://example.com/root.json",
|
||||
"definitions": {
|
||||
"A": { "id": "#foo" },
|
||||
"B": {
|
||||
"id": "other.json",
|
||||
"definitions": {
|
||||
"X": { "id": "#bar" },
|
||||
"Y": { "id": "t/inner.json" }
|
||||
}
|
||||
},
|
||||
"C": {
|
||||
"id": "urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f"
|
||||
},
|
||||
"single": {
|
||||
"id": "#item",
|
||||
"type": "integer"
|
||||
},
|
||||
"a": {"type": "integer"},
|
||||
"b": {"$ref": "#/definitions/a"},
|
||||
"c": {"$ref": "#/definitions/b"},
|
||||
"remote": { "$ref": "http://localhost:1234/subSchemas.json#/refToInteger" }
|
||||
},
|
||||
|
||||
"items": {
|
||||
"type": "array",
|
||||
"items": [ { "$ref": "#item" }, { "$ref": "other.json#bar" } ]
|
||||
}
|
||||
}
|
||||
3
test/issue-9/CMakeLists.txt
Normal file
3
test/issue-9/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
||||
add_test_simple_schema(Issue::9
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/base.json
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/instance.json)
|
||||
13
test/issue-9/bar.json
Normal file
13
test/issue-9/bar.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Describes bar",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
test/issue-9/base.json
Normal file
9
test/issue-9/base.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Describes foo",
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
{ "$ref": "bar.json" },
|
||||
{ "$ref": "foo/foo.json" }
|
||||
]
|
||||
}
|
||||
5
test/issue-9/foo/baz/baz.json
Normal file
5
test/issue-9/foo/baz/baz.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Describes baz",
|
||||
"$ref": "qux/qux.json"
|
||||
}
|
||||
13
test/issue-9/foo/baz/qux/qux.json
Normal file
13
test/issue-9/foo/baz/qux/qux.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Describes qux",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
test/issue-9/foo/foo.json
Normal file
5
test/issue-9/foo/foo.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
"description": "Describes foo",
|
||||
"$ref": "baz/baz.json"
|
||||
}
|
||||
3
test/issue-9/instance.json
Normal file
3
test/issue-9/instance.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "name"
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
PWD=$(realpath `dirname $0`/../JSON-Schema-Test-Suite/tests/draft4)
|
||||
|
||||
TESTS=`find $PWD | grep json$`
|
||||
|
||||
FAILCOUNT=0
|
||||
|
||||
for T in $TESTS
|
||||
do
|
||||
./json-schema-test < $T
|
||||
FAILCOUNT=$(($FAILCOUNT + $?))
|
||||
done
|
||||
|
||||
echo $FAILCOUNT tests failed
|
||||
|
||||
156
test/uri.cpp
Normal file
156
test/uri.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* JSON schema validator for JSON for modern C++
|
||||
*
|
||||
* Copyright (c) 2016-2019 Patrick Boettcher <p@yai.se>.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
*/
|
||||
#include <cstdlib>
|
||||
#include <json-schema.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using nlohmann::json;
|
||||
using nlohmann::json_uri;
|
||||
|
||||
static int errors;
|
||||
|
||||
#define EXPECT_EQ(a, b) \
|
||||
do { \
|
||||
if (a.to_string() != b) { \
|
||||
std::cerr << "Failed: '" << a << "' != '" << b << "'\n"; \
|
||||
errors++; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// test-schema taken from spec with modifications
|
||||
auto schema = R"(
|
||||
{
|
||||
"$id": "http://example.com/root.json",
|
||||
"definitions": {
|
||||
"A": { "$id": "#foo" },
|
||||
"B": {
|
||||
"$id": "other.json",
|
||||
"definitions": {
|
||||
"X": { "$id": "#bar" },
|
||||
"Y": { "$id": "t/inner.json" }
|
||||
}
|
||||
},
|
||||
"C": {
|
||||
"$id": "urn:uuid:ee564b8a-7a87-4125-8c96-e9f123d6766f",
|
||||
"definitions": {
|
||||
"Z": { "$id": "#bar" },
|
||||
"9": { "$id": "http://example.com/drole.json" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)"_json;
|
||||
|
||||
// resolve all refs
|
||||
class store
|
||||
{
|
||||
public:
|
||||
std::vector<json> schemas_;
|
||||
std::map<nlohmann::json_uri, const json *> schema_store_;
|
||||
|
||||
public:
|
||||
void insert_schema(json &s, std::vector<nlohmann::json_uri> base_uris)
|
||||
{
|
||||
auto id = s.find("$id");
|
||||
if (id != s.end())
|
||||
base_uris.push_back(base_uris.back().derive(id.value()));
|
||||
|
||||
for (auto &u : base_uris)
|
||||
schema_store_[u] = &s;
|
||||
|
||||
for (auto i = s.begin();
|
||||
i != s.end();
|
||||
++i) {
|
||||
|
||||
switch (i.value().type()) {
|
||||
case json::value_t::object: { // child is object, thus a schema
|
||||
std::vector<nlohmann::json_uri> subschema_uri = base_uris;
|
||||
|
||||
for (auto &ss : subschema_uri)
|
||||
ss = ss.append(nlohmann::json_uri::escape(i.key()));
|
||||
|
||||
insert_schema(i.value(), subschema_uri);
|
||||
} break;
|
||||
|
||||
case json::value_t::string:
|
||||
// this schema is a reference
|
||||
if (i.key() == "$ref") {
|
||||
auto id = base_uris.back().derive(i.value());
|
||||
i.value() = id.to_string();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//static void store_test(void)
|
||||
//{
|
||||
// store s;
|
||||
//
|
||||
// s.insert_schema(schema, {{""}});
|
||||
//
|
||||
// for (auto &i : s.schema_store_) {
|
||||
// std::cerr << i.first << " " << *i.second << "\n";
|
||||
// }
|
||||
//}
|
||||
|
||||
static void paths(json_uri start,
|
||||
const std::string &full,
|
||||
const std::string &full_path,
|
||||
const std::string &no_path)
|
||||
{
|
||||
EXPECT_EQ(start, full + " # ");
|
||||
|
||||
auto a = start.derive("other.json");
|
||||
EXPECT_EQ(a, full_path + "/other.json # ");
|
||||
|
||||
auto b = a.derive("base.json");
|
||||
EXPECT_EQ(b, full_path + "/base.json # ");
|
||||
|
||||
auto c = b.derive("subdir/base.json");
|
||||
EXPECT_EQ(c, full_path + "/subdir/base.json # ");
|
||||
|
||||
auto d = c.derive("subdir2/base.json");
|
||||
EXPECT_EQ(d, full_path + "/subdir/subdir2/base.json # ");
|
||||
|
||||
auto e = c.derive("/subdir2/base.json");
|
||||
EXPECT_EQ(e, no_path + "/subdir2/base.json # ");
|
||||
|
||||
auto f = c.derive("new.json");
|
||||
EXPECT_EQ(f, full_path + "/subdir/new.json # ");
|
||||
|
||||
auto g = c.derive("/new.json");
|
||||
EXPECT_EQ(g, no_path + "/new.json # ");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
json_uri empty("");
|
||||
paths(empty,
|
||||
"",
|
||||
"",
|
||||
"");
|
||||
|
||||
json_uri http("http://json-schema.org/draft-07/schema#");
|
||||
paths(http,
|
||||
"http://json-schema.org/draft-07/schema",
|
||||
"http://json-schema.org/draft-07",
|
||||
"http://json-schema.org");
|
||||
|
||||
// plain name fragments instead of JSON-pointers, are not supported, yet
|
||||
//store_test();
|
||||
|
||||
return errors;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user