glideapps / quicktype

Generate types and converters from JSON, Schema, and GraphQL
https://app.quicktype.io
Apache License 2.0
11.76k stars 1.04k forks source link

Fix cpp constraints #2614

Open PMLavigne opened 1 month ago

PMLavigne commented 1 month ago

Description

Motivation and Context

Generating C++ code from a JSON schema that had constraints would generate code to handle the constraints, but set all the constraint values to null (thus bypassing them entirely).

Previous Behaviour / Output

Given this JSON Schema as input:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$ref": "#/definitions/Test",
  "definitions": {
    "Test": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "testProp": {
          "type": "number",
          "minimum": 0.0,
          "maximum": 1.0
        },
        "testPropInt": {
          "type": "integer",
          "minimum": 0,
          "maximum": 1
        },
        "testPropString": {
          "type": "string",
          "minLength": 0,
          "maxLength": 1
        }
      },
      "required": [
      ],
      "title": "Test"
    }
  }
}

Quicktype would generate the following C++ class initializer (details vary depending on settings, but the symptom is always the same):

...
class Test {
    public:
    Test() :
        test_prop_constraint(boost::none, boost::none, boost::none, boost::none, boost::none, boost::none, boost::none),
        test_prop_int_constraint(boost::none, boost::none, boost::none, boost::none, boost::none, boost::none, boost::none),
        test_prop_string_constraint(boost::none, boost::none, boost::none, boost::none, boost::none, 1, boost::none)
    {}
...

Note how the constraint objects are initialized entirely with "none" values, or in the case of test_prop_string_constraint the 0 is ignored (in the string's case, a minimum length check of 0 isn't actually that useful, but it shows another hidden bug that I can't really demonstrate on the other types in the original code: that if a value of 0 is specified, it's ignored due to only checking for truthiness)

New Behaviour / Output

Given the same input above, quicktype now generates the following:

...
class Test {
    public:
    Test() :
        test_prop_constraint(boost::none, boost::none, 0, 1, boost::none, boost::none, boost::none),
        test_prop_int_constraint(0, 1, boost::none, boost::none, boost::none, boost::none, boost::none),
        test_prop_string_constraint(boost::none, boost::none, boost::none, boost::none, 0, 1, boost::none)
    {}
...

Note that the constraints are actually correctly filled out this time.

How Has This Been Tested?

Tested using the above test schema, as well as the actual schema for my project (which I can't post publicly, sorry).