@@ -323,6 +323,199 @@ TEST_F(Canonicalizer201909Test, exclusive_minimum_integer_to_minimum_3) {
323323 CANONICALIZE_AND_VALIDATE (document, expected, *compiled_meta_);
324324}
325325
326+ TEST_F (Canonicalizer201909Test, incoherent_exclusive_limits_1) {
327+ auto document = sourcemeta::core::parse_json (R"JSON( {
328+ "$schema": "https://json-schema.org/draft/2019-09/schema",
329+ "exclusiveMinimum": 3,
330+ "exclusiveMaximum": 3
331+ })JSON" );
332+
333+ const auto expected = sourcemeta::core::parse_json (R"JSON( {
334+ "$schema": "https://json-schema.org/draft/2019-09/schema",
335+ "not": { "type": "number" }
336+ })JSON" );
337+
338+ CANONICALIZE_AND_VALIDATE (document, expected, *compiled_meta_);
339+ }
340+
341+ TEST_F (Canonicalizer201909Test, incoherent_exclusive_limits_2) {
342+ auto document = sourcemeta::core::parse_json (R"JSON( {
343+ "$schema": "https://json-schema.org/draft/2019-09/schema",
344+ "exclusiveMinimum": 5,
345+ "exclusiveMaximum": 2
346+ })JSON" );
347+
348+ const auto expected = sourcemeta::core::parse_json (R"JSON( {
349+ "$schema": "https://json-schema.org/draft/2019-09/schema",
350+ "not": { "type": "number" }
351+ })JSON" );
352+
353+ CANONICALIZE_AND_VALIDATE (document, expected, *compiled_meta_);
354+ }
355+
356+ TEST_F (Canonicalizer201909Test, incoherent_exclusive_limits_3) {
357+ auto document = sourcemeta::core::parse_json (R"JSON( {
358+ "$schema": "https://json-schema.org/draft/2019-09/schema",
359+ "exclusiveMinimum": 5,
360+ "exclusiveMaximum": 2,
361+ "not": { "type": "string" }
362+ })JSON" );
363+
364+ const auto expected = sourcemeta::core::parse_json (R"JSON( {
365+ "$schema": "https://json-schema.org/draft/2019-09/schema",
366+ "allOf": [
367+ {
368+ "not": { "type": "string", "minLength": 0 }
369+ },
370+ {
371+ "not": { "type": "number" }
372+ }
373+ ]
374+ })JSON" );
375+
376+ CANONICALIZE_AND_VALIDATE (document, expected, *compiled_meta_);
377+ }
378+
379+ TEST_F (Canonicalizer201909Test, incoherent_exclusive_limits_4) {
380+ auto document = sourcemeta::core::parse_json (R"JSON( {
381+ "$schema": "https://json-schema.org/draft/2019-09/schema",
382+ "$ref": "#/$defs/test/additionalProperties",
383+ "$defs": {
384+ "test": {
385+ "additionalProperties": {
386+ "type": "string"
387+ },
388+ "exclusiveMaximum": 5,
389+ "exclusiveMinimum": 8
390+ }
391+ }
392+ })JSON" );
393+
394+ const auto expected = sourcemeta::core::parse_json (R"JSON( {
395+ "$schema": "https://json-schema.org/draft/2019-09/schema",
396+ "$defs": {
397+ "test": {
398+ "allOf": [
399+ {
400+ "not": { "type": "number" }
401+ },
402+ {
403+ "anyOf": [
404+ {
405+ "enum": [ null ]
406+ },
407+ {
408+ "enum": [ false, true ]
409+ },
410+ {
411+ "type": "object",
412+ "additionalProperties": {
413+ "type": "string",
414+ "minLength": 0
415+ },
416+ "patternProperties": {},
417+ "propertyNames": true,
418+ "minProperties": 0,
419+ "properties": {}
420+ },
421+ {
422+ "type": "array",
423+ "uniqueItems": false,
424+ "minItems": 0,
425+ "contains": true,
426+ "minContains": 0,
427+ "items": true
428+ },
429+ {
430+ "type": "string",
431+ "minLength": 0
432+ },
433+ {
434+ "type": "number"
435+ }
436+ ]
437+ }
438+ ]
439+ }
440+ },
441+ "allOf": [
442+ {
443+ "$ref": "#/$defs/test/allOf/1/anyOf/2/additionalProperties"
444+ }
445+ ]
446+ })JSON" );
447+
448+ CANONICALIZE_AND_VALIDATE (document, expected, *compiled_meta_);
449+ }
450+
451+ TEST_F (Canonicalizer201909Test, incoherent_exclusive_limits_5) {
452+ auto document = sourcemeta::core::parse_json (R"JSON( {
453+ "$schema": "https://json-schema.org/draft/2019-09/schema",
454+ "type": "number",
455+ "exclusiveMinimum": 5,
456+ "exclusiveMaximum": 2
457+ })JSON" );
458+
459+ const auto expected = sourcemeta::core::parse_json (R"JSON( {
460+ "$schema": "https://json-schema.org/draft/2019-09/schema",
461+ "not": true
462+ })JSON" );
463+
464+ CANONICALIZE_AND_VALIDATE (document, expected, *compiled_meta_);
465+ }
466+
467+ TEST_F (Canonicalizer201909Test, incoherent_exclusive_limits_6) {
468+ auto document = sourcemeta::core::parse_json (R"JSON( {
469+ "$schema": "https://json-schema.org/draft/2019-09/schema",
470+ "type": "integer",
471+ "exclusiveMinimum": 5,
472+ "exclusiveMaximum": 2
473+ })JSON" );
474+
475+ const auto expected = sourcemeta::core::parse_json (R"JSON( {
476+ "$schema": "https://json-schema.org/draft/2019-09/schema",
477+ "not": true
478+ })JSON" );
479+
480+ CANONICALIZE_AND_VALIDATE (document, expected, *compiled_meta_);
481+ }
482+
483+ TEST_F (Canonicalizer201909Test, incoherent_exclusive_limits_7) {
484+ auto document = sourcemeta::core::parse_json (R"JSON( {
485+ "$schema": "https://json-schema.org/draft/2019-09/schema",
486+ "type": ["string", "number"],
487+ "exclusiveMinimum": 5,
488+ "exclusiveMaximum": 2
489+ })JSON" );
490+
491+ const auto expected = sourcemeta::core::parse_json (R"JSON( {
492+ "$schema": "https://json-schema.org/draft/2019-09/schema",
493+ "type": "string",
494+ "minLength": 0
495+ })JSON" );
496+
497+ CANONICALIZE_AND_VALIDATE (document, expected, *compiled_meta_);
498+ }
499+
500+ TEST_F (Canonicalizer201909Test, incoherent_exclusive_limits_8) {
501+ auto document = sourcemeta::core::parse_json (R"JSON( {
502+ "$schema": "https://json-schema.org/draft/2019-09/schema",
503+ "allOf": [ { "type": "string" } ],
504+ "exclusiveMinimum": 5,
505+ "exclusiveMaximum": 2
506+ })JSON" );
507+
508+ const auto expected = sourcemeta::core::parse_json (R"JSON( {
509+ "$schema": "https://json-schema.org/draft/2019-09/schema",
510+ "allOf": [
511+ { "type": "string", "minLength": 0 },
512+ { "not": { "type": "number" } }
513+ ]
514+ })JSON" );
515+
516+ CANONICALIZE_AND_VALIDATE (document, expected, *compiled_meta_);
517+ }
518+
326519TEST_F (Canonicalizer201909Test, exclusive_minimum_integer_to_minimum_5) {
327520 auto document = sourcemeta::core::parse_json (R"JSON( {
328521 "$schema": "https://json-schema.org/draft/2019-09/schema",
0 commit comments