danielaparker / jsoncons

A C++, header-only library for constructing JSON and JSON-like data formats, with JSON Pointer, JSON Patch, JSON Schema, JSONPath, JMESPath, CSV, MessagePack, CBOR, BSON, UBJSON
https://danielaparker.github.io/jsoncons
Other
697 stars 160 forks source link

JSON schema format validation does not work correctly #501

Closed roszakg closed 4 months ago

roszakg commented 4 months ago

For the following schema:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "/test_schema",
  "type": "object",
  "properties": {
    "Date": {
      "type": "string",
      "format": "date-time"
    }
  },
  "required" : ["Date"],
  "unevaluatedProperties" : false
}

the validation of the following file passes (even though it should not:

{
    "Date" : "2024-03-19T26:34:56Z"
}

I'm using the master branch.

I looked at the std::unique_ptr<format_validator<Json>> make_format_validator(...) implementation with the debugger and what is surprising is the in the following part of the code (from schema_builder.hpp):

   auto schema_location = context.make_schema_path_with("format");

   std::string format = sch.template as<std::string>();

   format_checker format_check;
   if (format == "date-time")
     {
      format_check = rfc3339_date_time_check;
     }

when the schema_location equals /test_schema#/properties/Date/format then the format equals {"type\":\"string\",\"format\":\"date-time\"}".

There is no way this satisfies the "date-time" comparison directly below.

Can you please have a look?

Thank you,

danielaparker commented 4 months ago

You're right, there was an issue with "format" for drafts 2019-09 and 2020-12. Now fixed on master.

#include <jsoncons/json.hpp>
#include <jsoncons_ext/jsonschema/jsonschema.hpp>
#include <iostream>

using jsoncons::json;
using jsoncons::ojson;
namespace jsonschema = jsoncons::jsonschema;

int main()
{
    std::string schema_str = R"(
{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id" : "/test_schema", "type" : "object", "properties" : { "Date": { "type": "string", "format" : "date-time" } }, "required" : ["Date"] , "unevaluatedProperties" : false }
)";
    json schema = json::parse(schema_str);

    auto compiled = jsoncons::jsonschema::make_json_schema(schema,
        jsonschema::evaluation_options{}.require_format_validation(true));

    std::string data_str = R"(
{ "Date" : "2024-03-19T26:34:56Z" }
)";
    json data = json::parse(data_str);

    jsoncons::json_decoder<ojson> decoder;
    compiled.validate(data, decoder);
    std::cout << pretty_print(decoder.get_result()) << "\n";
}

Output:

[
    {
        "valid": false,
        "evaluationPath": "/properties/Date/format",
        "schemaLocation": "/test_schema#/properties/Date/format",
        "instanceLocation": "/Date",
        "error": "'2024-03-19T26:34:56Z' is not a RFC 3339 date-time string."
    },
    {
        "valid": false,
        "evaluationPath": "/unevaluatedProperties/Date",
        "schemaLocation": "/test_schema",
        "instanceLocation": "/Date",
        "error": "Unevaluated property 'Date' but the schema does not allow unevaluated properties."
    }
]
roszakg commented 4 months ago

Thank you - that's amazing :) I was planning to submit a PR, but you were faster.

I really appreciate your help.