From 5d211ce1af36f7f390e06053d49e7737652362ce Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 28 Sep 2026 17:06:12 -0300 Subject: [PATCH 1/3] Cover legacy JSON Schema applicators and an invalid identifier Signed-off-by: Juan Cruz Viotti --- .../jsonschema/jsonschema_frame_error_test.cc | 22 +++++++++++++ test/jsonschema/jsonschema_frame_test.cc | 32 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/test/jsonschema/jsonschema_frame_error_test.cc b/test/jsonschema/jsonschema_frame_error_test.cc index a52be9ae8..88cf792bc 100644 --- a/test/jsonschema/jsonschema_frame_error_test.cc +++ b/test/jsonschema/jsonschema_frame_error_test.cc @@ -2639,3 +2639,25 @@ TEST(draft7_root_id_fragment_invalid_leading_digit_root_mode) { FAIL(); } } + +TEST(identifier_that_is_not_a_valid_uri) { + const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/schema", + "$defs": { + "inner": { "$id": "//[::44.1" } + } + })JSON"); + + try { + [[maybe_unused]] const sourcemeta::core::SchemaFrame frame{ + sourcemeta::core::SchemaFrame::Mode::References, document, + sourcemeta::core::schema_walker, sourcemeta::core::schema_resolver}; + FAIL(); + } catch (const sourcemeta::core::SchemaKeywordError &error) { + EXPECT_EQ(error.keyword(), "$id"); + EXPECT_EQ(error.value(), "//[::44.1"); + } catch (...) { + FAIL(); + } +} diff --git a/test/jsonschema/jsonschema_frame_test.cc b/test/jsonschema/jsonschema_frame_test.cc index b8a699c6d..45bb4f476 100644 --- a/test/jsonschema/jsonschema_frame_test.cc +++ b/test/jsonschema/jsonschema_frame_test.cc @@ -2072,3 +2072,35 @@ TEST(accessors_metaschema_unresolvable) { "Could not resolve the metaschema of the schema"); } } + +TEST(draft2_requires_applies_to_the_parent_instance) { + const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-02/schema#", + "properties": { + "one": { "requires": { "type": "string" } } + } + })JSON"); + + const sourcemeta::core::SchemaFrame frame{ + sourcemeta::core::SchemaFrame::Mode::References, document, + sourcemeta::core::schema_walker, sourcemeta::core::schema_resolver}; + + const sourcemeta::core::Pointer subschema{"properties", "one", "requires"}; + EXPECT_TRUE( + frame.traverse(sourcemeta::core::to_weak_pointer(subschema)).has_value()); +} + +TEST(draft3_disallow_holding_a_schema) { + const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "disallow": [ { "type": "string" }, "null" ] + })JSON"); + + const sourcemeta::core::SchemaFrame frame{ + sourcemeta::core::SchemaFrame::Mode::References, document, + sourcemeta::core::schema_walker, sourcemeta::core::schema_resolver}; + + const sourcemeta::core::Pointer subschema{"disallow", 0}; + EXPECT_TRUE( + frame.traverse(sourcemeta::core::to_weak_pointer(subschema)).has_value()); +} From 7506b521eef3b221843d1a8aeada2a5e410c59af Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 28 Sep 2026 17:13:14 -0300 Subject: [PATCH 2/3] More Signed-off-by: Juan Cruz Viotti --- .../draft2/requires_holding_a_schema.json | 159 ++++++++++++++++++ .../draft3/disallow_holding_a_schema.json | 158 +++++++++++++++++ test/jsonschema/jsonschema_frame_test.cc | 32 ---- 3 files changed, 317 insertions(+), 32 deletions(-) create mode 100644 test/jsonschema/frame/draft2/requires_holding_a_schema.json create mode 100644 test/jsonschema/frame/draft3/disallow_holding_a_schema.json diff --git a/test/jsonschema/frame/draft2/requires_holding_a_schema.json b/test/jsonschema/frame/draft2/requires_holding_a_schema.json new file mode 100644 index 000000000..e23c550b0 --- /dev/null +++ b/test/jsonschema/frame/draft2/requires_holding_a_schema.json @@ -0,0 +1,159 @@ +{ + "schema": { + "$schema": "http://json-schema.org/draft-02/schema#", + "properties": { + "one": { + "requires": { + "type": "string" + } + } + } + }, + "root": { + "mode": "root", + "locations": { + "static": { + "": { + "parent": null, + "type": "subschema", + "root": null, + "base": "", + "pointer": "", + "relativePointer": "", + "dialect": "http://json-schema.org/draft-02/schema#", + "baseDialect": "http://json-schema.org/draft-02/hyper-schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-02/schema#": true + } + } + }, + "dynamic": {} + }, + "references": [] + }, + "pointers": { + "mode": "pointers", + "locations": { + "static": { + "": { + "parent": null, + "type": "subschema", + "root": null, + "base": "", + "pointer": "", + "relativePointer": "", + "dialect": "http://json-schema.org/draft-02/schema#", + "baseDialect": "http://json-schema.org/draft-02/hyper-schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-02/schema#": true + } + }, + "#/$schema": { + "parent": "", + "type": "pointer", + "root": null, + "base": "", + "pointer": "/$schema", + "relativePointer": "/$schema", + "dialect": "http://json-schema.org/draft-02/schema#", + "baseDialect": "http://json-schema.org/draft-02/hyper-schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-02/schema#": true + } + }, + "#/properties": { + "parent": "", + "type": "pointer", + "root": null, + "base": "", + "pointer": "/properties", + "relativePointer": "/properties", + "dialect": "http://json-schema.org/draft-02/schema#", + "baseDialect": "http://json-schema.org/draft-02/hyper-schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-02/schema#": true + } + }, + "#/properties/one": { + "parent": "", + "type": "subschema", + "root": null, + "base": "", + "pointer": "/properties/one", + "relativePointer": "/properties/one", + "dialect": "http://json-schema.org/draft-02/schema#", + "baseDialect": "http://json-schema.org/draft-02/hyper-schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-02/schema#": true + } + }, + "#/properties/one/requires": { + "parent": "/properties/one", + "type": "subschema", + "root": null, + "base": "", + "pointer": "/properties/one/requires", + "relativePointer": "/properties/one/requires", + "dialect": "http://json-schema.org/draft-02/schema#", + "baseDialect": "http://json-schema.org/draft-02/hyper-schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-02/schema#": true + } + }, + "#/properties/one/requires/type": { + "parent": "/properties/one/requires", + "type": "pointer", + "root": null, + "base": "", + "pointer": "/properties/one/requires/type", + "relativePointer": "/properties/one/requires/type", + "dialect": "http://json-schema.org/draft-02/schema#", + "baseDialect": "http://json-schema.org/draft-02/hyper-schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-02/schema#": true + } + } + }, + "dynamic": {} + }, + "references": [ + { + "type": "static", + "origin": "/$schema", + "original": "http://json-schema.org/draft-02/schema#", + "destination": "http://json-schema.org/draft-02/schema", + "base": "http://json-schema.org/draft-02/schema", + "fragment": null + } + ] + }, + "standalone": true +} diff --git a/test/jsonschema/frame/draft3/disallow_holding_a_schema.json b/test/jsonschema/frame/draft3/disallow_holding_a_schema.json new file mode 100644 index 000000000..480464f79 --- /dev/null +++ b/test/jsonschema/frame/draft3/disallow_holding_a_schema.json @@ -0,0 +1,158 @@ +{ + "schema": { + "$schema": "http://json-schema.org/draft-03/schema#", + "disallow": [ + { + "type": "string" + }, + "null" + ] + }, + "root": { + "mode": "root", + "locations": { + "static": { + "": { + "parent": null, + "type": "subschema", + "root": null, + "base": "", + "pointer": "", + "relativePointer": "", + "dialect": "http://json-schema.org/draft-03/schema#", + "baseDialect": "http://json-schema.org/draft-03/schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-03/schema#": true + } + } + }, + "dynamic": {} + }, + "references": [] + }, + "pointers": { + "mode": "pointers", + "locations": { + "static": { + "": { + "parent": null, + "type": "subschema", + "root": null, + "base": "", + "pointer": "", + "relativePointer": "", + "dialect": "http://json-schema.org/draft-03/schema#", + "baseDialect": "http://json-schema.org/draft-03/schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-03/schema#": true + } + }, + "#/$schema": { + "parent": "", + "type": "pointer", + "root": null, + "base": "", + "pointer": "/$schema", + "relativePointer": "/$schema", + "dialect": "http://json-schema.org/draft-03/schema#", + "baseDialect": "http://json-schema.org/draft-03/schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-03/schema#": true + } + }, + "#/disallow": { + "parent": "", + "type": "pointer", + "root": null, + "base": "", + "pointer": "/disallow", + "relativePointer": "/disallow", + "dialect": "http://json-schema.org/draft-03/schema#", + "baseDialect": "http://json-schema.org/draft-03/schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-03/schema#": true + } + }, + "#/disallow/0": { + "parent": "", + "type": "subschema", + "root": null, + "base": "", + "pointer": "/disallow/0", + "relativePointer": "/disallow/0", + "dialect": "http://json-schema.org/draft-03/schema#", + "baseDialect": "http://json-schema.org/draft-03/schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-03/schema#": true + } + }, + "#/disallow/0/type": { + "parent": "/disallow/0", + "type": "pointer", + "root": null, + "base": "", + "pointer": "/disallow/0/type", + "relativePointer": "/disallow/0/type", + "dialect": "http://json-schema.org/draft-03/schema#", + "baseDialect": "http://json-schema.org/draft-03/schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-03/schema#": true + } + }, + "#/disallow/1": { + "parent": "", + "type": "pointer", + "root": null, + "base": "", + "pointer": "/disallow/1", + "relativePointer": "/disallow/1", + "dialect": "http://json-schema.org/draft-03/schema#", + "baseDialect": "http://json-schema.org/draft-03/schema#", + "propertyName": false, + "orphan": false, + "hasReferencesTo": false, + "hasReferencesThrough": false, + "vocabularies": { + "http://json-schema.org/draft-03/schema#": true + } + } + }, + "dynamic": {} + }, + "references": [ + { + "type": "static", + "origin": "/$schema", + "original": "http://json-schema.org/draft-03/schema#", + "destination": "http://json-schema.org/draft-03/schema", + "base": "http://json-schema.org/draft-03/schema", + "fragment": null + } + ] + }, + "standalone": true +} diff --git a/test/jsonschema/jsonschema_frame_test.cc b/test/jsonschema/jsonschema_frame_test.cc index 45bb4f476..b8a699c6d 100644 --- a/test/jsonschema/jsonschema_frame_test.cc +++ b/test/jsonschema/jsonschema_frame_test.cc @@ -2072,35 +2072,3 @@ TEST(accessors_metaschema_unresolvable) { "Could not resolve the metaschema of the schema"); } } - -TEST(draft2_requires_applies_to_the_parent_instance) { - const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ - "$schema": "http://json-schema.org/draft-02/schema#", - "properties": { - "one": { "requires": { "type": "string" } } - } - })JSON"); - - const sourcemeta::core::SchemaFrame frame{ - sourcemeta::core::SchemaFrame::Mode::References, document, - sourcemeta::core::schema_walker, sourcemeta::core::schema_resolver}; - - const sourcemeta::core::Pointer subschema{"properties", "one", "requires"}; - EXPECT_TRUE( - frame.traverse(sourcemeta::core::to_weak_pointer(subschema)).has_value()); -} - -TEST(draft3_disallow_holding_a_schema) { - const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ - "$schema": "http://json-schema.org/draft-03/schema#", - "disallow": [ { "type": "string" }, "null" ] - })JSON"); - - const sourcemeta::core::SchemaFrame frame{ - sourcemeta::core::SchemaFrame::Mode::References, document, - sourcemeta::core::schema_walker, sourcemeta::core::schema_resolver}; - - const sourcemeta::core::Pointer subschema{"disallow", 0}; - EXPECT_TRUE( - frame.traverse(sourcemeta::core::to_weak_pointer(subschema)).has_value()); -} From 34c0b8ff3f07b7e6d93cacfb698aa5407a293e81 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 28 Sep 2026 17:22:56 -0300 Subject: [PATCH 3/3] Fix Signed-off-by: Juan Cruz Viotti --- test/jsonschema/jsonschema_frame_error_test.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jsonschema/jsonschema_frame_error_test.cc b/test/jsonschema/jsonschema_frame_error_test.cc index 88cf792bc..4fd3fd889 100644 --- a/test/jsonschema/jsonschema_frame_error_test.cc +++ b/test/jsonschema/jsonschema_frame_error_test.cc @@ -2655,6 +2655,7 @@ TEST(identifier_that_is_not_a_valid_uri) { sourcemeta::core::schema_walker, sourcemeta::core::schema_resolver}; FAIL(); } catch (const sourcemeta::core::SchemaKeywordError &error) { + EXPECT_STREQ(error.what(), "The identifier is not a valid URI"); EXPECT_EQ(error.keyword(), "$id"); EXPECT_EQ(error.value(), "//[::44.1"); } catch (...) {