tristanpenman / valijson

Header-only C++ library for JSON Schema validation, with support for many popular parsers
BSD 2-Clause "Simplified" License
345 stars 104 forks source link

False validation errors with the yaml-cpp adapter #178

Open jacquev6 opened 1 year ago

jacquev6 commented 1 year ago

Hello and thank you for this library!

I get false validation errors for schemas with a type constraint for boolean, number and integer when using the yaml-cpp adapter. See code below to reproduce the issue.

I believe this is because the isBool, isDouble, isInteger, isNumber and isString methods in yaml_cpp_adapter.hpp return literal trues and falses.

Code to reproduce the issue:

#include <valijson/adapters/yaml_cpp_adapter.hpp>
#include <valijson/schema_parser.hpp>
#include <valijson/validator.hpp>

void validate(const std::string& schema_string, const std::string& document_string) {
  std::istringstream schema_iss(schema_string);
  YAML::Node schema_node = YAML::Load(schema_iss);
  valijson::SchemaParser schema_parser;
  valijson::adapters::YamlCppAdapter schema_adapter(schema_node);
  valijson::Schema schema;
  schema_parser.populateSchema(schema_adapter, schema);

  std::istringstream document_iss(document_string);
  YAML::Node document_node = YAML::Load(document_iss);
  valijson::adapters::YamlCppAdapter document_adapter(document_node);

  valijson::Validator validator;
  valijson::ValidationResults results;
  if (validator.validate(schema, document_adapter, &results)) {
    std::cout << "OK";
  } else {
    std::cout << "VALIDATION ERROR:";
    valijson::ValidationResults::Error error;
    while (results.popError(error)) {
      std::cout << "\n -";
      for (const std::string &contextElement : error.context) {
          std::cout << " " << contextElement;
      }
      std::cout << ": " << error.description;
    }
  }
  std::cout << std::endl;
}

int main() {
  // OK
  validate("type: string", "\"bonjour\"");
  validate("type: array", "[]");
  validate("type: object", "{}");
  // <root>: Value type not permitted by 'type' constraint.
  validate("type: boolean", "true");
  validate("type: integer", "42");
  validate("type: number", "49.3");
}

Thank you!

jacquev6 commented 1 year ago

Maybe you could try the conversion and catch the BadConversion but I'm not familiar enough with either yaml-ccp or valijson to be sure that's the right way. Something like:

    bool isInteger() const
    {
        try {
            m_value.as<int64_t>();
            return true;
        } catch (const YAML::BadConversion&) {
            return false;
        }
    }