From e6e28679c172cb60d5ae586d6ada6dfaba78d53a Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 4 May 2026 19:12:20 -0400 Subject: [PATCH 1/4] Support `definitions` in Draft 3 The official test suite uses it. Signed-off-by: Juan Cruz Viotti --- src/core/jsonschema/bundle.cc | 3 +- src/core/jsonschema/helpers.h | 13 +- src/core/jsonschema/known_walker.cc | 4 + .../jsonschema_bundle_draft3_test.cc | 293 +++++++++++++++++- .../jsonschema_frame_draft3_test.cc | 44 +++ .../jsonschema_walker_draft3_test.cc | 25 ++ 6 files changed, 379 insertions(+), 3 deletions(-) diff --git a/src/core/jsonschema/bundle.cc b/src/core/jsonschema/bundle.cc index 2a1361042..7c8e09521 100644 --- a/src/core/jsonschema/bundle.cc +++ b/src/core/jsonschema/bundle.cc @@ -454,10 +454,11 @@ auto bundle(JSON &schema, const SchemaWalker &walker, if (ref_overrides_adjacent_keywords(schema_base_dialect.value()) && schema.is_object() && schema.defines("$ref")) { if (schema.size() == 1) { + const auto applicator{allof_keyword(schema_base_dialect.value())}; auto branches{JSON::make_array()}; branches.push_back(schema); schema.at("$ref").into(std::move(branches)); - schema.rename("$ref", "allOf"); + schema.rename("$ref", JSON::String{applicator}); } else { throw SchemaError( "Cannot bundle a JSON Schema Draft 7 or older with a top-level " diff --git a/src/core/jsonschema/helpers.h b/src/core/jsonschema/helpers.h index ad2635552..dd3866c64 100644 --- a/src/core/jsonschema/helpers.h +++ b/src/core/jsonschema/helpers.h @@ -48,9 +48,9 @@ inline auto definitions_keyword(const SchemaBaseDialect base_dialect) case SchemaBaseDialect::JSON_Schema_Draft_6_Hyper: case SchemaBaseDialect::JSON_Schema_Draft_4: case SchemaBaseDialect::JSON_Schema_Draft_4_Hyper: - return "definitions"; case SchemaBaseDialect::JSON_Schema_Draft_3: case SchemaBaseDialect::JSON_Schema_Draft_3_Hyper: + return "definitions"; case SchemaBaseDialect::JSON_Schema_Draft_2_Hyper: case SchemaBaseDialect::JSON_Schema_Draft_1_Hyper: case SchemaBaseDialect::JSON_Schema_Draft_0_Hyper: @@ -61,6 +61,17 @@ inline auto definitions_keyword(const SchemaBaseDialect base_dialect) return "$defs"; } +inline auto allof_keyword(const SchemaBaseDialect base_dialect) + -> std::string_view { + switch (base_dialect) { + case SchemaBaseDialect::JSON_Schema_Draft_3: + case SchemaBaseDialect::JSON_Schema_Draft_3_Hyper: + return "extends"; + default: + return "allOf"; + } +} + // In older drafts, the presence of `$ref` would override any sibling keywords // See // https://json-schema.org/draft-07/draft-handrews-json-schema-01#rfc.section.8.3 diff --git a/src/core/jsonschema/known_walker.cc b/src/core/jsonschema/known_walker.cc index b31b23b53..f439eb5d4 100644 --- a/src/core/jsonschema/known_walker.cc +++ b/src/core/jsonschema/known_walker.cc @@ -154,6 +154,10 @@ auto handle_definitions(const Vocabularies &vocabularies) LocationMembers, "$ref") CHECK_VOCABULARY_WITH_DEPENDENCIES(Known::JSON_Schema_Draft_4_Hyper, {}, LocationMembers, "$ref") + CHECK_VOCABULARY_WITH_DEPENDENCIES(Known::JSON_Schema_Draft_3, {}, + LocationMembers, "$ref") + CHECK_VOCABULARY_WITH_DEPENDENCIES(Known::JSON_Schema_Draft_3_Hyper, {}, + LocationMembers, "$ref") return UNKNOWN_RESULT; } diff --git a/test/jsonschema/jsonschema_bundle_draft3_test.cc b/test/jsonschema/jsonschema_bundle_draft3_test.cc index 52a891971..d4bfacaef 100644 --- a/test/jsonschema/jsonschema_bundle_draft3_test.cc +++ b/test/jsonschema/jsonschema_bundle_draft3_test.cc @@ -14,6 +14,32 @@ static auto test_resolver(std::string_view identifier) "id": "https://www.sourcemeta.com/test-1", "type": "string" })JSON"); + } else if (identifier == "https://www.sourcemeta.com/test-2") { + return sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-2", + "extends": { "$ref": "test-3" } + })JSON"); + } else if (identifier == "https://www.sourcemeta.com/test-3") { + return sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-3", + "extends": { "$ref": "test-1" } + })JSON"); + } else if (identifier == "https://www.sourcemeta.com/test-4") { + return sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-4", + "type": "boolean" + })JSON"); + } else if (identifier == "https://www.sourcemeta.com/recursive") { + return sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/recursive", + "properties": { + "foo": { "$ref": "#" } + } + })JSON"); } else { return sourcemeta::core::schema_resolver(identifier); } @@ -58,7 +84,272 @@ TEST(JSONSchema_bundle_draft3, simple_bundling) { } })JSON"); + sourcemeta::core::bundle(document, sourcemeta::core::schema_walker, + test_resolver); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "test": { "$ref": "https://www.sourcemeta.com/test-1" } + }, + "definitions": { + "https://www.sourcemeta.com/test-1": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-1", + "type": "string" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_bundle_draft3, simple_with_id) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "foo": { "$ref": "https://www.sourcemeta.com/test-1" }, + "bar": { + "id": "https://www.sourcemeta.com", + "extends": { "$ref": "test-2" } + } + } + })JSON"); + + sourcemeta::core::bundle(document, sourcemeta::core::schema_walker, + test_resolver); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "foo": { "$ref": "https://www.sourcemeta.com/test-1" }, + "bar": { + "id": "https://www.sourcemeta.com", + "extends": { "$ref": "test-2" } + } + }, + "definitions": { + "https://www.sourcemeta.com/test-1": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-1", + "type": "string" + }, + "https://www.sourcemeta.com/test-2": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-2", + "extends": { "$ref": "test-3" } + }, + "https://www.sourcemeta.com/test-3": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-3", + "extends": { "$ref": "test-1" } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_bundle_draft3, schema_not_found) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "foo": { "$ref": "https://www.sourcemeta.com/xxx" } + } + })JSON"); + EXPECT_THROW(sourcemeta::core::bundle( document, sourcemeta::core::schema_walker, test_resolver), - sourcemeta::core::SchemaError); + sourcemeta::core::SchemaResolutionError); +} + +TEST(JSONSchema_bundle_draft3, idempotency) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "test": { "$ref": "https://www.sourcemeta.com/test-2" } + } + })JSON"); + + sourcemeta::core::bundle(document, sourcemeta::core::schema_walker, + test_resolver); + sourcemeta::core::bundle(document, sourcemeta::core::schema_walker, + test_resolver); + sourcemeta::core::bundle(document, sourcemeta::core::schema_walker, + test_resolver); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "test": { "$ref": "https://www.sourcemeta.com/test-2" } + }, + "definitions": { + "https://www.sourcemeta.com/test-1": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-1", + "type": "string" + }, + "https://www.sourcemeta.com/test-2": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-2", + "extends": { "$ref": "test-3" } + }, + "https://www.sourcemeta.com/test-3": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-3", + "extends": { "$ref": "test-1" } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_bundle_draft3, pre_embedded) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "test": { "$ref": "https://www.sourcemeta.com/test-2" } + }, + "definitions": { + "already-embedded": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-1", + "type": "string" + } + } + })JSON"); + + sourcemeta::core::bundle(document, sourcemeta::core::schema_walker, + test_resolver); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "test": { "$ref": "https://www.sourcemeta.com/test-2" } + }, + "definitions": { + "already-embedded": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-1", + "type": "string" + }, + "https://www.sourcemeta.com/test-2": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-2", + "extends": { "$ref": "test-3" } + }, + "https://www.sourcemeta.com/test-3": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-3", + "extends": { "$ref": "test-1" } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_bundle_draft3, taken_definitions_entry) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "test": { "$ref": "https://www.sourcemeta.com/test-1" }, + "extra": { "$ref": "https://www.sourcemeta.com/test-4" } + }, + "definitions": { + "https://www.sourcemeta.com/test-1": { "type": "object" }, + "https://www.sourcemeta.com/test-4": { "type": "object" }, + "https://www.sourcemeta.com/test-4/x": { "type": "object" }, + "https://www.sourcemeta.com/test-4/x/x": { "type": "object" } + } + })JSON"); + + sourcemeta::core::bundle(document, sourcemeta::core::schema_walker, + test_resolver); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "id": "https://example.com", + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "test": { "$ref": "https://www.sourcemeta.com/test-1" }, + "extra": { "$ref": "https://www.sourcemeta.com/test-4" } + }, + "definitions": { + "https://www.sourcemeta.com/test-1": { "type": "object" }, + "https://www.sourcemeta.com/test-1/x": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-1", + "type": "string" + }, + "https://www.sourcemeta.com/test-4": { "type": "object" }, + "https://www.sourcemeta.com/test-4/x": { "type": "object" }, + "https://www.sourcemeta.com/test-4/x/x": { "type": "object" }, + "https://www.sourcemeta.com/test-4/x/x/x": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-4", + "type": "boolean" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_bundle_draft3, recursive) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "extends": { "$ref": "https://www.sourcemeta.com/recursive" } + })JSON"); + + sourcemeta::core::bundle(document, sourcemeta::core::schema_walker, + test_resolver); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "extends": { "$ref": "https://www.sourcemeta.com/recursive" }, + "definitions": { + "https://www.sourcemeta.com/recursive": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/recursive", + "properties": { + "foo": { "$ref": "#" } + } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_bundle_draft3, standalone_ref_with_default_dialect) { + sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$ref": "https://www.sourcemeta.com/test-1" + })JSON"); + + sourcemeta::core::bundle(document, sourcemeta::core::schema_walker, + test_resolver, + "http://json-schema.org/draft-03/schema#"); + + const sourcemeta::core::JSON expected = sourcemeta::core::parse_json(R"JSON({ + "extends": [ { "$ref": "https://www.sourcemeta.com/test-1" } ], + "definitions": { + "https://www.sourcemeta.com/test-1": { + "$schema": "http://json-schema.org/draft-03/schema#", + "id": "https://www.sourcemeta.com/test-1", + "type": "string" + } + } + })JSON"); + + EXPECT_EQ(document, expected); } diff --git a/test/jsonschema/jsonschema_frame_draft3_test.cc b/test/jsonschema/jsonschema_frame_draft3_test.cc index 182048cb9..1778d18a3 100644 --- a/test/jsonschema/jsonschema_frame_draft3_test.cc +++ b/test/jsonschema/jsonschema_frame_draft3_test.cc @@ -942,3 +942,47 @@ TEST(JSONSchema_frame_draft3, id_fragment_invalid_whitespace) { FAIL(); } } + +TEST(JSONSchema_frame_draft3, definitions_subschemas) { + const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "definitions": { + "string": { "type": "string" } + } + })JSON"); + + sourcemeta::core::SchemaFrame frame{ + sourcemeta::core::SchemaFrame::Mode::References}; + frame.analyse(document, sourcemeta::core::schema_walker, + sourcemeta::core::schema_resolver); + + EXPECT_EQ(frame.locations().size(), 5); + + EXPECT_ANONYMOUS_FRAME_STATIC_SUBSCHEMA( + frame, "", "", "http://json-schema.org/draft-03/schema#", + JSON_Schema_Draft_3, std::nullopt, false, false); + EXPECT_ANONYMOUS_FRAME_STATIC_POINTER( + frame, "#/$schema", "/$schema", "http://json-schema.org/draft-03/schema#", + JSON_Schema_Draft_3, "", false, false); + EXPECT_ANONYMOUS_FRAME_STATIC_POINTER( + frame, "#/definitions", "/definitions", + "http://json-schema.org/draft-03/schema#", JSON_Schema_Draft_3, "", false, + false); + EXPECT_ANONYMOUS_FRAME_STATIC_SUBSCHEMA( + frame, "#/definitions/string", "/definitions/string", + "http://json-schema.org/draft-03/schema#", JSON_Schema_Draft_3, "", false, + true); + EXPECT_ANONYMOUS_FRAME_STATIC_POINTER( + frame, "#/definitions/string/type", "/definitions/string/type", + "http://json-schema.org/draft-03/schema#", JSON_Schema_Draft_3, + "/definitions/string", false, true); + + EXPECT_EQ(frame.references().size(), 1); + + EXPECT_STATIC_REFERENCE( + frame, "/$schema", "http://json-schema.org/draft-03/schema", + "http://json-schema.org/draft-03/schema", std::nullopt, + "http://json-schema.org/draft-03/schema#"); + + EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "", frame.root()); +} diff --git a/test/jsonschema/jsonschema_walker_draft3_test.cc b/test/jsonschema/jsonschema_walker_draft3_test.cc index db399714d..2b981cdb7 100644 --- a/test/jsonschema/jsonschema_walker_draft3_test.cc +++ b/test/jsonschema/jsonschema_walker_draft3_test.cc @@ -48,6 +48,31 @@ TEST(JSONSchema_walker_draft3, ref) { EXPECT_TRUE(result.instances.none()); } +TEST(JSONSchema_walker_draft3, definitions) { + using namespace sourcemeta::core; + const auto &result{schema_walker("definitions", VOCABULARIES_DRAFT3)}; + EXPECT_EQ(result.type, SchemaKeywordType::LocationMembers); + EXPECT_TRUE(result.vocabulary.has_value()); + EXPECT_VOCABULARY_KNOWN(result.vocabulary.value(), JSON_Schema_Draft_3); + const std::unordered_set expected{"$ref"}; + EXPECT_EQ(result.dependencies, expected); + EXPECT_TRUE(result.order_dependencies.empty()); + EXPECT_TRUE(result.instances.none()); +} + +TEST(JSONSchema_walker_draft3_hyperschema, definitions) { + using namespace sourcemeta::core; + const auto &result{ + schema_walker("definitions", VOCABULARIES_DRAFT3_HYPERSCHEMA)}; + EXPECT_EQ(result.type, SchemaKeywordType::LocationMembers); + EXPECT_TRUE(result.vocabulary.has_value()); + EXPECT_VOCABULARY_KNOWN(result.vocabulary.value(), JSON_Schema_Draft_3_Hyper); + const std::unordered_set expected{"$ref"}; + EXPECT_EQ(result.dependencies, expected); + EXPECT_TRUE(result.order_dependencies.empty()); + EXPECT_TRUE(result.instances.none()); +} + TEST(JSONSchema_walker_draft3, items) { using namespace sourcemeta::core; const auto &result{schema_walker("items", VOCABULARIES_DRAFT3)}; From 3036401c1b60595c0b965ac99a9ddc911a568c97 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 4 May 2026 21:06:26 -0400 Subject: [PATCH 2/4] Fixes Signed-off-by: Juan Cruz Viotti --- src/core/jsonschema/bundle.cc | 7 +++++-- src/core/jsonschema/helpers.h | 11 ----------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/core/jsonschema/bundle.cc b/src/core/jsonschema/bundle.cc index 7c8e09521..cb6eb7239 100644 --- a/src/core/jsonschema/bundle.cc +++ b/src/core/jsonschema/bundle.cc @@ -454,11 +454,14 @@ auto bundle(JSON &schema, const SchemaWalker &walker, if (ref_overrides_adjacent_keywords(schema_base_dialect.value()) && schema.is_object() && schema.defines("$ref")) { if (schema.size() == 1) { - const auto applicator{allof_keyword(schema_base_dialect.value())}; + const auto is_draft3{schema_base_dialect.value() == + SchemaBaseDialect::JSON_Schema_Draft_3 || + schema_base_dialect.value() == + SchemaBaseDialect::JSON_Schema_Draft_3_Hyper}; auto branches{JSON::make_array()}; branches.push_back(schema); schema.at("$ref").into(std::move(branches)); - schema.rename("$ref", JSON::String{applicator}); + schema.rename("$ref", is_draft3 ? "extends" : "allOf"); } else { throw SchemaError( "Cannot bundle a JSON Schema Draft 7 or older with a top-level " diff --git a/src/core/jsonschema/helpers.h b/src/core/jsonschema/helpers.h index dd3866c64..b3ca84fa2 100644 --- a/src/core/jsonschema/helpers.h +++ b/src/core/jsonschema/helpers.h @@ -61,17 +61,6 @@ inline auto definitions_keyword(const SchemaBaseDialect base_dialect) return "$defs"; } -inline auto allof_keyword(const SchemaBaseDialect base_dialect) - -> std::string_view { - switch (base_dialect) { - case SchemaBaseDialect::JSON_Schema_Draft_3: - case SchemaBaseDialect::JSON_Schema_Draft_3_Hyper: - return "extends"; - default: - return "allOf"; - } -} - // In older drafts, the presence of `$ref` would override any sibling keywords // See // https://json-schema.org/draft-07/draft-handrews-json-schema-01#rfc.section.8.3 From 2be0ce52b7fec21857da727065edb3ecfd07f189 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 4 May 2026 21:09:35 -0400 Subject: [PATCH 3/4] More Signed-off-by: Juan Cruz Viotti --- .../jsonschema_frame_draft3_test.cc | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/test/jsonschema/jsonschema_frame_draft3_test.cc b/test/jsonschema/jsonschema_frame_draft3_test.cc index 1778d18a3..7f77b0e5b 100644 --- a/test/jsonschema/jsonschema_frame_draft3_test.cc +++ b/test/jsonschema/jsonschema_frame_draft3_test.cc @@ -986,3 +986,68 @@ TEST(JSONSchema_frame_draft3, definitions_subschemas) { EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "", frame.root()); } + +TEST(JSONSchema_frame_draft3, ref_into_definitions) { + const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({ + "$schema": "http://json-schema.org/draft-03/schema#", + "properties": { + "foo": { "$ref": "#/definitions/string" } + }, + "definitions": { + "string": { "type": "string" } + } + })JSON"); + + sourcemeta::core::SchemaFrame frame{ + sourcemeta::core::SchemaFrame::Mode::References}; + frame.analyse(document, sourcemeta::core::schema_walker, + sourcemeta::core::schema_resolver); + + EXPECT_EQ(frame.locations().size(), 8); + + EXPECT_ANONYMOUS_FRAME_STATIC_SUBSCHEMA( + frame, "", "", "http://json-schema.org/draft-03/schema#", + JSON_Schema_Draft_3, std::nullopt, false, false); + EXPECT_ANONYMOUS_FRAME_STATIC_POINTER( + frame, "#/$schema", "/$schema", "http://json-schema.org/draft-03/schema#", + JSON_Schema_Draft_3, "", false, false); + EXPECT_ANONYMOUS_FRAME_STATIC_POINTER( + frame, "#/properties", "/properties", + "http://json-schema.org/draft-03/schema#", JSON_Schema_Draft_3, "", false, + false); + EXPECT_ANONYMOUS_FRAME_STATIC_SUBSCHEMA( + frame, "#/properties/foo", "/properties/foo", + "http://json-schema.org/draft-03/schema#", JSON_Schema_Draft_3, "", false, + false); + EXPECT_ANONYMOUS_FRAME_STATIC_POINTER( + frame, "#/properties/foo/$ref", "/properties/foo/$ref", + "http://json-schema.org/draft-03/schema#", JSON_Schema_Draft_3, + "/properties/foo", false, false); + EXPECT_ANONYMOUS_FRAME_STATIC_POINTER( + frame, "#/definitions", "/definitions", + "http://json-schema.org/draft-03/schema#", JSON_Schema_Draft_3, "", false, + false); + EXPECT_ANONYMOUS_FRAME_STATIC_SUBSCHEMA( + frame, "#/definitions/string", "/definitions/string", + "http://json-schema.org/draft-03/schema#", JSON_Schema_Draft_3, "", false, + true); + EXPECT_ANONYMOUS_FRAME_STATIC_POINTER( + frame, "#/definitions/string/type", "/definitions/string/type", + "http://json-schema.org/draft-03/schema#", JSON_Schema_Draft_3, + "/definitions/string", false, true); + + EXPECT_EQ(frame.references().size(), 2); + + EXPECT_STATIC_REFERENCE( + frame, "/$schema", "http://json-schema.org/draft-03/schema", + "http://json-schema.org/draft-03/schema", std::nullopt, + "http://json-schema.org/draft-03/schema#"); + EXPECT_STATIC_REFERENCE(frame, "/properties/foo/$ref", "#/definitions/string", + "", "/definitions/string", "#/definitions/string"); + + EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "", frame.root()); + EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "#/properties/foo", + frame.root()); + EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "#/definitions/string", + frame.root()); +} From b1a7cee4770bb3b6ddff89a14e8049ee3f8217a1 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Mon, 4 May 2026 21:10:58 -0400 Subject: [PATCH 4/4] More Signed-off-by: Juan Cruz Viotti --- test/jsonschema/jsonschema_frame_draft3_test.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/jsonschema/jsonschema_frame_draft3_test.cc b/test/jsonschema/jsonschema_frame_draft3_test.cc index 7f77b0e5b..08d8c8fec 100644 --- a/test/jsonschema/jsonschema_frame_draft3_test.cc +++ b/test/jsonschema/jsonschema_frame_draft3_test.cc @@ -985,6 +985,10 @@ TEST(JSONSchema_frame_draft3, definitions_subschemas) { "http://json-schema.org/draft-03/schema#"); EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "", frame.root()); + EXPECT_FRAME_LOCATION_NON_REACHABLE(frame, Static, "#/definitions/string", + frame.root()); + EXPECT_FRAME_LOCATION_REACHABLE(frame, Static, "#/definitions/string", + "#/definitions/string"); } TEST(JSONSchema_frame_draft3, ref_into_definitions) {