hypothesis-jsonschema icon indicating copy to clipboard operation
hypothesis-jsonschema copied to clipboard

Failing test_canonicalises_to_equivalent_fixpoint

Open Stranger6667 opened this issue 5 years ago • 2 comments

Currently the test_canonicalises_to_equivalent_fixpoint test fails on assert cc == canonicalish(cc) with the following schema:

schema = {'not': {'anyOf': [{'type': 'number'}, {'if': {'type': 'null'}, 'then': {'type': 'null'}, 'else': {}}]}}

As far as I see, calling canonicalise second time should not transform the schema again. But here is schema after the first call:

{
    "not": {"anyOf": [{"const": None}, {"not": {"const": None}}]},
    "type": ["null", "boolean", "string", "array", "object"],
}

and after the second call:

{
    "not": {
        "anyOf": [
            {"const": None},
            {
                "type": ["null", "boolean", "string", "array", "object"],
                "not": {"const": None},
            },
        ]
    },
    "type": ["null", "boolean", "string", "array", "object"],
}

git bisect gave me this commit - afc292b9a2873a0c33176e61829c3dde25139333

Should the second call leave the input schema as is?

Stranger6667 avatar Aug 26 '20 19:08 Stranger6667

Hmm. This schema should in fact canonicalise to {"not": {}}, because {"anyOf": [S1, {"not": S2}]} should canonicalise to {} for any schemas where merged([S1, S2]) == S1. This is the main thing to fix.

It would also be nice to express that not: {const: None} excludes type: null, and likewise for enums containing None or both booleans.

In the process, we should overhaul our corpus-based tests: keep the valid and invalid inputs for the test suite schemas and check that their status doesn't change by canonicalising. We might want to do this with submodules, given the size of the schemastore corpus (see https://github.com/Zac-HD/hypothesis-jsonschema/compare/catalog-update).

Zac-HD avatar Aug 27 '20 04:08 Zac-HD

A simpler example - consider the three schemas A, B, and C:

A = {'not': {'anyOf': [{'type': 'number'}, {'type': 'integer'}]}}
B = {'type': ['null', 'boolean', 'string', 'array', 'object'], 'not': {'type': 'integer'}}
C = {'type': ['null', 'boolean', 'string', 'array', 'object']}

C is the canonical form. B canonicalises to C, correctly. However A canonicalises to B, instead of directly to C!

Zac-HD avatar Sep 30 '20 07:09 Zac-HD