Merge remote-tracking branch 'origin/master' into json_pointer-pop-push
This commit is contained in:
commit
11b188cfef
@ -60,7 +60,7 @@ script:
|
|||||||
- $CXX --version
|
- $CXX --version
|
||||||
|
|
||||||
# put json.hpp to nlohmann
|
# put json.hpp to nlohmann
|
||||||
- mkdir -p nlohmann && wget https://github.com/nlohmann/json/releases/download/v3.5.0/json.hpp -O nlohmann/json.hpp
|
- mkdir -p nlohmann && wget https://github.com/nlohmann/json/releases/download/v3.6.0/json.hpp -O nlohmann/json.hpp
|
||||||
|
|
||||||
# compile and execute unit tests
|
# compile and execute unit tests
|
||||||
- mkdir -p build && cd build
|
- mkdir -p build && cd build
|
||||||
|
|||||||
@ -46,7 +46,8 @@ set_target_properties(json-schema-validator
|
|||||||
|
|
||||||
install(TARGETS json-schema-validator
|
install(TARGETS json-schema-validator
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
ARCHIVE DESTINATION lib)
|
ARCHIVE DESTINATION lib
|
||||||
|
RUNTIME DESTINATION bin)
|
||||||
|
|
||||||
install(DIRECTORY src/
|
install(DIRECTORY src/
|
||||||
DESTINATION include
|
DESTINATION include
|
||||||
@ -59,12 +60,13 @@ target_include_directories(json-schema-validator
|
|||||||
target_compile_features(json-schema-validator
|
target_compile_features(json-schema-validator
|
||||||
PUBLIC
|
PUBLIC
|
||||||
cxx_range_for) # for C++11 - flags
|
cxx_range_for) # for C++11 - flags
|
||||||
# Enable more compiler warnings, except when using Visual Studio compiler
|
|
||||||
if(NOT MSVC)
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
target_compile_options(json-schema-validator
|
target_compile_options(json-schema-validator
|
||||||
PRIVATE
|
PRIVATE
|
||||||
-Wall -Wextra)
|
-Wall -Wextra)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(json-schema-validator
|
target_link_libraries(json-schema-validator
|
||||||
PUBLIC
|
PUBLIC
|
||||||
json-hpp)
|
json-hpp)
|
||||||
|
|||||||
20
README.md
20
README.md
@ -10,7 +10,7 @@ This is a C++ library for validating JSON documents based on a
|
|||||||
[draft-7 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
|
First a disclaimer: *It is work in progress and
|
||||||
contributions or hints or discussions are welcome.* Even though a 2.0.0 release is immenent.
|
contributions or hints or discussions are welcome.* Even though a 2.0.0 release is imminent.
|
||||||
|
|
||||||
Niels Lohmann et al develop a great JSON parser for C++ called [JSON for Modern
|
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
|
C++](https://github.com/nlohmann/json). This validator is based on this
|
||||||
@ -21,7 +21,7 @@ is rather simple.
|
|||||||
|
|
||||||
# New in version 2
|
# New in version 2
|
||||||
|
|
||||||
Although significant changes have been coorporate to the 2 version
|
Although significant changes have been done for the 2nd version
|
||||||
(a complete rewrite) the API is compatible with the 1.0.0 release. Except for
|
(a complete rewrite) the API is compatible with the 1.0.0 release. Except for
|
||||||
the namespace which is now `nlohmann::json_schema.
|
the namespace which is now `nlohmann::json_schema.
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ Version **2** supports JSON schema draft 7, whereas 1 was supporting draft 4
|
|||||||
only. Please update your schemas.
|
only. Please update your schemas.
|
||||||
|
|
||||||
The primary change in 2 is the way a schema is used. While in version 1 the schema was
|
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
|
kept as a JSON-document and used again and again during validation, in version 2 the schema
|
||||||
is parsed into compiled C++ objects which are then used during validation. There are surely
|
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
|
still optimizations to be done, but validation speed has improved by factor 100
|
||||||
or more.
|
or more.
|
||||||
@ -42,9 +42,9 @@ 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
|
By default this is done with exceptions thrown at the users with a helpful
|
||||||
message telling what's wrong with the document while validating.
|
message telling what's wrong with the document while validating.
|
||||||
|
|
||||||
With **2.0.0** the user can pass a `json_scheam::basic_error_handler` derived object
|
With **2.0.0** the user can pass a `json_scheam::basic_error_handler`-derived
|
||||||
along with the instance to validate to receive a each time a validation error occurs
|
object along with the instance to validate to receive a callback each time a
|
||||||
and decice what to do (throwing, counting, collecting).
|
validation error occurs and decide what to do (throwing, counting, collecting).
|
||||||
|
|
||||||
Another goal was to use Niels Lohmann's JSON-library. This is why the validator
|
Another goal was to use Niels Lohmann's JSON-library. This is why the validator
|
||||||
lives in his namespace.
|
lives in his namespace.
|
||||||
@ -55,12 +55,12 @@ Numerical validation uses nlohmann integer, unsigned and floating point types, d
|
|||||||
the schema type is "integer" or "number". Bignum (i.e. arbitrary precision and
|
the schema type is "integer" or "number". Bignum (i.e. arbitrary precision and
|
||||||
range) is not supported at this time.
|
range) is not supported at this time.
|
||||||
|
|
||||||
Currently JSON-URI with "plain name fragments" are not supported. So referring to an URI
|
Currently JSON-URI with "plain name fragments" are not supported: referring to an URI
|
||||||
with `$ref: "file.json#plain"` will not work.
|
with `$ref: "file.json#plain"` will not work.
|
||||||
|
|
||||||
# How to use
|
# How to use
|
||||||
|
|
||||||
The current state of the build-system needs at least version **3.5.0** of NLohmann's
|
The current state of the build-system needs at least version **3.6.0** of NLohmann's
|
||||||
JSON library. It is looking for the `json.hpp` within a `nlohmann/`-path.
|
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
|
When build the library you need to provide the path to the directory where the include-file
|
||||||
@ -167,7 +167,7 @@ int main()
|
|||||||
std::cout << "About to validate this person:\n"
|
std::cout << "About to validate this person:\n"
|
||||||
<< std::setw(2) << person << std::endl;
|
<< std::setw(2) << person << std::endl;
|
||||||
try {
|
try {
|
||||||
validator.validate(person); // validate the document
|
validator.validate(person); // validate the document - uses the default throwing error-handler
|
||||||
std::cout << "Validation succeeded\n";
|
std::cout << "Validation succeeded\n";
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << "Validation failed, here is why: " << e.what() << "\n";
|
std::cerr << "Validation failed, here is why: " << e.what() << "\n";
|
||||||
@ -190,7 +190,7 @@ int main()
|
|||||||
<< std::setw(2) << person << std::endl;
|
<< std::setw(2) << person << std::endl;
|
||||||
|
|
||||||
custom_error_handler err;
|
custom_error_handler err;
|
||||||
validator.validate(person, err); // validate the document - uses the default throwing error-handler
|
validator.validate(person, err); // validate the document
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
std::cerr << "Validation failed\n";
|
std::cerr << "Validation failed\n";
|
||||||
|
|||||||
@ -55,7 +55,7 @@ int main()
|
|||||||
std::cout << "About to validate this person:\n"
|
std::cout << "About to validate this person:\n"
|
||||||
<< std::setw(2) << person << std::endl;
|
<< std::setw(2) << person << std::endl;
|
||||||
try {
|
try {
|
||||||
validator.validate(person); // validate the document
|
validator.validate(person); // validate the document - uses the default throwing error-handler
|
||||||
std::cout << "Validation succeeded\n";
|
std::cout << "Validation succeeded\n";
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
std::cerr << "Validation failed, here is why: " << e.what() << "\n";
|
std::cerr << "Validation failed, here is why: " << e.what() << "\n";
|
||||||
@ -78,7 +78,7 @@ int main()
|
|||||||
<< std::setw(2) << person << std::endl;
|
<< std::setw(2) << person << std::endl;
|
||||||
|
|
||||||
custom_error_handler err;
|
custom_error_handler err;
|
||||||
validator.validate(person, err); // validate the document - uses the default throwing error-handler
|
validator.validate(person, err); // validate the document
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
std::cerr << "Validation failed\n";
|
std::cerr << "Validation failed\n";
|
||||||
|
|||||||
@ -24,11 +24,11 @@
|
|||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
#ifdef NLOHMANN_JSON_VERSION_MAJOR
|
#ifdef NLOHMANN_JSON_VERSION_MAJOR
|
||||||
# if NLOHMANN_JSON_VERSION_MAJOR < 3 || NLOHMANN_JSON_VERSION_MINOR < 5 || NLOHMANN_JSON_VERSION_PATCH < 1
|
# if (NLOHMANN_JSON_VERSION_MAJOR * 10000 + NLOHMANN_JSON_VERSION_MINOR * 100 + NLOHMANN_JSON_VERSION_PATCH) < 30600
|
||||||
# error "Please use this library with NLohmann's JSON version 3.5.1 or higher"
|
# error "Please use this library with NLohmann's JSON version 3.6.0 or higher"
|
||||||
# endif
|
# endif
|
||||||
#else
|
#else
|
||||||
# error "expected existing NLOHMANN_JSON_VERSION_MAJOR preproc variable, please update to NLohmann's JSON 3.5.1"
|
# error "expected existing NLOHMANN_JSON_VERSION_MAJOR preproc variable, please update to NLohmann's JSON 3.6.0"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// make yourself a home - welcome to nlohmann's namespace
|
// make yourself a home - welcome to nlohmann's namespace
|
||||||
@ -51,7 +51,7 @@ class JSON_SCHEMA_VALIDATOR_API json_uri
|
|||||||
std::string proto_;
|
std::string proto_;
|
||||||
std::string hostname_;
|
std::string hostname_;
|
||||||
std::string path_;
|
std::string path_;
|
||||||
nlohmann::json::json_pointer pointer_;
|
json::json_pointer pointer_;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// decodes a JSON uri and replaces all or part of the currently stored values
|
// decodes a JSON uri and replaces all or part of the currently stored values
|
||||||
@ -72,7 +72,7 @@ public:
|
|||||||
const std::string hostname() const { return hostname_; }
|
const std::string hostname() const { return hostname_; }
|
||||||
const std::string path() const { return path_; }
|
const std::string path() const { return path_; }
|
||||||
|
|
||||||
const nlohmann::json::json_pointer pointer() const { return pointer_; }
|
const json::json_pointer pointer() const { return pointer_; }
|
||||||
|
|
||||||
const std::string url() const { return location(); }
|
const std::string url() const { return location(); }
|
||||||
const std::string location() const;
|
const std::string location() const;
|
||||||
@ -92,7 +92,7 @@ public:
|
|||||||
json_uri append(const std::string &field) const
|
json_uri append(const std::string &field) const
|
||||||
{
|
{
|
||||||
json_uri u = *this;
|
json_uri u = *this;
|
||||||
u.pointer_.push_back(field);
|
u.pointer_ /= field;
|
||||||
return u;
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ class basic_error_handler
|
|||||||
bool error_{false};
|
bool error_{false};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void error(const nlohmann::json::json_pointer & /*path*/, const json & /* instance */, const std::string & /*message*/)
|
virtual void error(const json::json_pointer & /*path*/, const json & /* instance */, const std::string & /*message*/)
|
||||||
{
|
{
|
||||||
error_ = true;
|
error_ = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -91,7 +91,7 @@ void json_uri::update(const std::string &uri)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer_ = nlohmann::json::json_pointer(pointer);
|
pointer_ = json::json_pointer(pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string json_uri::location() const
|
const std::string json_uri::location() const
|
||||||
|
|||||||
@ -39,7 +39,7 @@ public:
|
|||||||
schema(root_schema *root)
|
schema(root_schema *root)
|
||||||
: root_(root) {}
|
: root_(root) {}
|
||||||
|
|
||||||
virtual void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const = 0;
|
virtual void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const = 0;
|
||||||
|
|
||||||
static std::shared_ptr<schema> make(json &schema,
|
static std::shared_ptr<schema> make(json &schema,
|
||||||
root_schema *root,
|
root_schema *root,
|
||||||
@ -52,7 +52,7 @@ class schema_ref : public schema
|
|||||||
const std::string id_;
|
const std::string id_;
|
||||||
std::shared_ptr<schema> target_;
|
std::shared_ptr<schema> target_;
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const final
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const final
|
||||||
{
|
{
|
||||||
if (target_)
|
if (target_)
|
||||||
target_->validate(ptr, instance, e);
|
target_->validate(ptr, instance, e);
|
||||||
@ -83,8 +83,8 @@ class root_schema : public schema
|
|||||||
std::shared_ptr<schema> root_;
|
std::shared_ptr<schema> root_;
|
||||||
|
|
||||||
struct schema_file {
|
struct schema_file {
|
||||||
std::map<nlohmann::json::json_pointer, std::shared_ptr<schema>> schemas;
|
std::map<json::json_pointer, std::shared_ptr<schema>> schemas;
|
||||||
std::map<nlohmann::json::json_pointer, std::shared_ptr<schema_ref>> unresolved; // contains all unresolved references from any other file seen during parsing
|
std::map<json::json_pointer, std::shared_ptr<schema_ref>> unresolved; // contains all unresolved references from any other file seen during parsing
|
||||||
json unknown_keywords;
|
json unknown_keywords;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ public:
|
|||||||
} while (1);
|
} while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const final
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const final
|
||||||
{
|
{
|
||||||
if (root_)
|
if (root_)
|
||||||
root_->validate(ptr, instance, e);
|
root_->validate(ptr, instance, e);
|
||||||
@ -230,7 +230,7 @@ class logical_not : public schema
|
|||||||
{
|
{
|
||||||
std::shared_ptr<schema> subschema_;
|
std::shared_ptr<schema> subschema_;
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const final
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const final
|
||||||
{
|
{
|
||||||
basic_error_handler err;
|
basic_error_handler err;
|
||||||
subschema_->validate(ptr, instance, err);
|
subschema_->validate(ptr, instance, err);
|
||||||
@ -260,7 +260,7 @@ class logical_combination : public schema
|
|||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<schema>> subschemata_;
|
std::vector<std::shared_ptr<schema>> subschemata_;
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const final
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const final
|
||||||
{
|
{
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
|
||||||
@ -268,27 +268,21 @@ class logical_combination : public schema
|
|||||||
basic_error_handler err;
|
basic_error_handler err;
|
||||||
s->validate(ptr, instance, err);
|
s->validate(ptr, instance, err);
|
||||||
|
|
||||||
if (err) {
|
if (!err)
|
||||||
//sub_schema_err << " one schema failed because: " << e.what() << "\n";
|
|
||||||
if (combine_logic == allOf) {
|
|
||||||
e.error(ptr, instance, "at least one schema has failed, but all of them are required to validate.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (combine_logic == oneOf && count > 1) {
|
if (is_validate_complete(instance, ptr, e, err, count))
|
||||||
e.error(ptr, instance, "more than one schema has succeeded, but exactly one of them is required to validate.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (combine_logic == anyOf && count == 1)
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((combine_logic == anyOf || combine_logic == oneOf) && count == 0)
|
if (count == 0)
|
||||||
e.error(ptr, instance, "no validation has succeeded but one of them is required to validate.");
|
e.error(ptr, instance, "no validation has succeeded but one of them is required to validate.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// specialized for each of the logical_combination_types
|
||||||
|
static const std::string key;
|
||||||
|
static bool is_validate_complete(const json &, const json::json_pointer &, basic_error_handler &, bool, size_t);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
logical_combination(json &sch,
|
logical_combination(json &sch,
|
||||||
root_schema *root,
|
root_schema *root,
|
||||||
@ -296,24 +290,43 @@ public:
|
|||||||
: schema(root)
|
: schema(root)
|
||||||
{
|
{
|
||||||
size_t c = 0;
|
size_t c = 0;
|
||||||
std::string key;
|
|
||||||
switch (combine_logic) {
|
|
||||||
case allOf:
|
|
||||||
key = "allOf";
|
|
||||||
break;
|
|
||||||
case oneOf:
|
|
||||||
key = "oneOf";
|
|
||||||
break;
|
|
||||||
case anyOf:
|
|
||||||
key = "anyOf";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &subschema : sch)
|
for (auto &subschema : sch)
|
||||||
subschemata_.push_back(schema::make(subschema, root, {key, std::to_string(c++)}, uris));
|
subschemata_.push_back(schema::make(subschema, root, {key, std::to_string(c++)}, uris));
|
||||||
|
|
||||||
|
// value of allOf, anyOf, and oneOf "MUST be a non-empty array"
|
||||||
|
// TODO error/throw? when subschemata_.empty()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
const std::string logical_combination<allOf>::key = "allOf";
|
||||||
|
template <>
|
||||||
|
const std::string logical_combination<anyOf>::key = "anyOf";
|
||||||
|
template <>
|
||||||
|
const std::string logical_combination<oneOf>::key = "oneOf";
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool logical_combination<allOf>::is_validate_complete(const json &instance, const json::json_pointer &ptr, basic_error_handler &e, bool err, size_t)
|
||||||
|
{
|
||||||
|
if (err)
|
||||||
|
e.error(ptr, instance, "at least one schema has failed, but all of them are required to validate.");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool logical_combination<anyOf>::is_validate_complete(const json &, const json::json_pointer &, basic_error_handler &, bool, size_t count)
|
||||||
|
{
|
||||||
|
return count == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
bool logical_combination<oneOf>::is_validate_complete(const json &instance, const json::json_pointer &ptr, basic_error_handler &e, bool, size_t count)
|
||||||
|
{
|
||||||
|
if (count > 1)
|
||||||
|
e.error(ptr, instance, "more than one schema has succeeded, but exactly one of them is required to validate.");
|
||||||
|
return count > 1;
|
||||||
|
}
|
||||||
|
|
||||||
class type_schema : public schema
|
class type_schema : public schema
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<schema>> type_;
|
std::vector<std::shared_ptr<schema>> type_;
|
||||||
@ -328,7 +341,7 @@ class type_schema : public schema
|
|||||||
|
|
||||||
std::shared_ptr<schema> if_, then_, else_;
|
std::shared_ptr<schema> if_, then_, else_;
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override final
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override final
|
||||||
{
|
{
|
||||||
// depending on the type of instance run the type specific validator - if present
|
// depending on the type of instance run the type specific validator - if present
|
||||||
auto type = type_[(uint8_t) instance.type()];
|
auto type = type_[(uint8_t) instance.type()];
|
||||||
@ -340,8 +353,8 @@ class type_schema : public schema
|
|||||||
|
|
||||||
if (enum_.first) {
|
if (enum_.first) {
|
||||||
bool seen_in_enum = false;
|
bool seen_in_enum = false;
|
||||||
for (auto &e : enum_.second)
|
for (auto &v : enum_.second)
|
||||||
if (instance == e) {
|
if (instance == v) {
|
||||||
seen_in_enum = true;
|
seen_in_enum = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -509,7 +522,7 @@ class string : public schema
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (minLength_.first) {
|
if (minLength_.first) {
|
||||||
if (utf8_length(instance) < minLength_.second) {
|
if (utf8_length(instance) < minLength_.second) {
|
||||||
@ -591,15 +604,15 @@ class numeric : public schema
|
|||||||
|
|
||||||
std::pair<bool, json::number_float_t> multipleOf_{false, 0};
|
std::pair<bool, json::number_float_t> multipleOf_{false, 0};
|
||||||
|
|
||||||
// multipleOf - if the rest of the division is 0 -> OK
|
// multipleOf - if the remainder of the division is 0 -> OK
|
||||||
bool violates_multiple_of(json::number_float_t x) const
|
bool violates_multiple_of(T x) const
|
||||||
{
|
{
|
||||||
json::number_integer_t n = static_cast<json::number_integer_t>(x / multipleOf_.second);
|
double res = std::remainder(x, multipleOf_.second);
|
||||||
double res = (x - n * multipleOf_.second);
|
double eps = std::nextafter(x, 0) - x;
|
||||||
return fabs(res) > std::numeric_limits<json::number_float_t>::epsilon();
|
return std::fabs(res) > std::fabs(eps);
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
||||||
{
|
{
|
||||||
T value = instance; // conversion of json to value_type
|
T value = instance; // conversion of json to value_type
|
||||||
|
|
||||||
@ -658,7 +671,7 @@ public:
|
|||||||
|
|
||||||
class null : public schema
|
class null : public schema
|
||||||
{
|
{
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (!instance.is_null())
|
if (!instance.is_null())
|
||||||
e.error(ptr, instance, "expected to be null");
|
e.error(ptr, instance, "expected to be null");
|
||||||
@ -671,7 +684,7 @@ public:
|
|||||||
|
|
||||||
class boolean_type : public schema
|
class boolean_type : public schema
|
||||||
{
|
{
|
||||||
void validate(const nlohmann::json::json_pointer &, const json &, basic_error_handler &) const override {}
|
void validate(const json::json_pointer &, const json &, basic_error_handler &) const override {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
boolean_type(json &, root_schema *root)
|
boolean_type(json &, root_schema *root)
|
||||||
@ -681,7 +694,7 @@ public:
|
|||||||
class boolean : public schema
|
class boolean : public schema
|
||||||
{
|
{
|
||||||
bool true_;
|
bool true_;
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (!true_) { // false schema
|
if (!true_) { // false schema
|
||||||
// empty array
|
// empty array
|
||||||
@ -705,7 +718,7 @@ class required : public schema
|
|||||||
{
|
{
|
||||||
const std::vector<std::string> required_;
|
const std::vector<std::string> required_;
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override final
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override final
|
||||||
{
|
{
|
||||||
for (auto &r : required_)
|
for (auto &r : required_)
|
||||||
if (instance.find(r) == instance.end())
|
if (instance.find(r) == instance.end())
|
||||||
@ -733,7 +746,7 @@ class object : public schema
|
|||||||
|
|
||||||
std::shared_ptr<schema> propertyNames_;
|
std::shared_ptr<schema> propertyNames_;
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (maxProperties_.first && instance.size() > maxProperties_.second)
|
if (maxProperties_.first && instance.size() > maxProperties_.second)
|
||||||
e.error(ptr, instance, "too many properties.");
|
e.error(ptr, instance, "too many properties.");
|
||||||
@ -771,7 +784,7 @@ class object : public schema
|
|||||||
|
|
||||||
for (auto &dep : dependencies_) {
|
for (auto &dep : dependencies_) {
|
||||||
auto prop = instance.find(dep.first);
|
auto prop = instance.find(dep.first);
|
||||||
if (prop != instance.end()) // if dependency-property is present in instance
|
if (prop != instance.end()) // if dependency-property is present in instance
|
||||||
dep.second->validate(ptr / dep.first, instance, e); // validate
|
dep.second->validate(ptr / dep.first, instance, e); // validate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -867,7 +880,7 @@ class array : public schema
|
|||||||
|
|
||||||
std::shared_ptr<schema> contains_;
|
std::shared_ptr<schema> contains_;
|
||||||
|
|
||||||
void validate(const nlohmann::json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
void validate(const json::json_pointer &ptr, const json &instance, basic_error_handler &e) const override
|
||||||
{
|
{
|
||||||
if (maxItems_.first && instance.size() > maxItems_.second)
|
if (maxItems_.first && instance.size() > maxItems_.second)
|
||||||
e.error(ptr, instance, "has too many items.");
|
e.error(ptr, instance, "has too many items.");
|
||||||
@ -1109,7 +1122,7 @@ void json_validator::validate(const json &instance)
|
|||||||
|
|
||||||
void json_validator::validate(const json &instance, basic_error_handler &err)
|
void json_validator::validate(const json &instance, basic_error_handler &err)
|
||||||
{
|
{
|
||||||
nlohmann::json::json_pointer ptr;
|
json::json_pointer ptr;
|
||||||
root_->validate(ptr, instance, err);
|
root_->validate(ptr, instance, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
test/issue-48/CMakeLists.txt
Normal file
3
test/issue-48/CMakeLists.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
add_test_simple_schema(Issue::48
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/schema.json
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/instance.json)
|
||||||
1
test/issue-48/instance.json
Normal file
1
test/issue-48/instance.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
1.2
|
||||||
3
test/issue-48/schema.json
Normal file
3
test/issue-48/schema.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"multipleOf": 0.1
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user