From 0e905c556a3677109ddaceba2f5548c2a2b8d130 Mon Sep 17 00:00:00 2001 From: Sven Fink Date: Thu, 5 Mar 2020 14:20:51 +0100 Subject: [PATCH] Defaults are not validated --- src/json-validator.cpp | 8 +++ test/issue-91.cpp | 119 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 test/issue-91.cpp diff --git a/src/json-validator.cpp b/src/json-validator.cpp index ee85e35..d77dbad 100644 --- a/src/json-validator.cpp +++ b/src/json-validator.cpp @@ -814,6 +814,7 @@ class object : public schema void validate(const json::json_pointer &ptr, json &instance, error_handler &e) const override { + std::set ignoredProperties{}; // reverse search for (auto const &prop : properties_) { const auto finding = instance.find(prop.first); @@ -821,6 +822,7 @@ class object : public schema const auto &defaultValue = prop.second->defaultValue(ptr, instance, e); if (!defaultValue.empty()) { // if default value is available instance[prop.first] = defaultValue; + ignoredProperties.emplace(prop.first); } } } @@ -842,6 +844,12 @@ class object : public schema propertyNames_->validate(ptr, v, e); } + const auto finding = ignoredProperties.find(p.key()); + if (ignoredProperties.end() != finding) { + // defaults shall not invalidate schemas + continue; + } + bool a_prop_or_pattern_matched = false; auto schema_p = properties_.find(p.key()); // check if it is in "properties" diff --git a/test/issue-91.cpp b/test/issue-91.cpp new file mode 100644 index 0000000..ac9e943 --- /dev/null +++ b/test/issue-91.cpp @@ -0,0 +1,119 @@ +#include +#include + +using nlohmann::json; +using nlohmann::json_schema::json_validator; + +static const json address_schema = R"( +{ + "type": "object", + "properties": { + "street_address": { + "type": "string" + }, + "country": { + "enum": ["United States of America", "Canada"], + "default": "Canada" + } + }, + "if": { + "properties": { "country": { "const": "United States of America" } } + }, + "then": { + "properties": { "postal_code": { "pattern": "[0-9]{5}(-[0-9]{4})?" } } + }, + "else": { + "properties": { "postal_code": { "pattern": "[A-Z][0-9][A-Z] [0-9][A-Z][0-9]" } } + } +})"_json; + +class expected_error_handler : public nlohmann::json_schema::basic_error_handler +{ + void error(const nlohmann::json_pointer> &pointer, const json &instance, + const std::string &message) override + { + hit_ = true; + } + + bool hit_{false}; + +public: + bool isHit() const { return hit_; } +}; + +class custom_error_handler : public nlohmann::json_schema::basic_error_handler +{ + void error(const nlohmann::json_pointer> &pointer, const json &instance, + const std::string &message) override + { + nlohmann::json_schema::basic_error_handler::error(pointer, instance, message); + std::cerr << "ERROR: '" << pointer << "' - '" << instance << "': " << message << "\n"; + hit_ = true; + } + + bool hit_{false}; + +public: + bool isHit() const { return hit_; } +}; + +int main(void) +{ + json_validator validator{}; + validator.set_root_schema(address_schema); + + { + custom_error_handler customErr{}; + const auto good_withCanada = R"({ + "street_address": "24 Sussex Drive", + "country": "Canada", + "postal_code": "K1M 1M4" + })"_json; + validator.validate(good_withCanada, customErr); + if (customErr.isHit()) { + return 1; + } + } + + { + custom_error_handler customErr{}; + const auto good_withDefaultCanada = R"({ + "street_address": "24 Sussex Drive", + "postal_code": "K1M 1M4" + })"_json; + validator.validate(good_withDefaultCanada, customErr); + if (customErr.isHit()) { + return 1; + } + } + + { + custom_error_handler customErr{}; + const auto good_Usa = R"({ + "street_address": "1600 Pennsylvania Avenue NW", + "country": "United States of America", + "postal_code": "20500" + })"_json; + validator.validate(good_Usa, customErr); + if (customErr.isHit()) { + return 1; + } + } + + { + expected_error_handler expErr{}; + const auto bad_Canada = R"({ + "street_address": "24 Sussex Drive", + "country": "Canada", + "postal_code": "10000" + })"_json; + + validator.validate(bad_Canada, expErr); + if (!expErr.isHit()) { + std::cerr << "Should have failed validating postal code" << std::endl; + return 1; + } + } + + return 0; +}