From f12546ffb77ec80b14cb2b38e2d5937eb61e891f Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Wed, 5 Feb 2025 11:17:02 -0400 Subject: [PATCH] Avoid copying subschemas in `SchemaIteratorEntry` (#1523) Signed-off-by: Juan Cruz Viotti --- src/core/jsonschema/frame.cc | 35 ++-- .../sourcemeta/core/jsonschema_types.h | 6 +- src/core/jsonschema/walker.cc | 28 ++- .../jsonschema_keyword_iterator_test.cc | 177 +++++++++--------- 4 files changed, 124 insertions(+), 122 deletions(-) diff --git a/src/core/jsonschema/frame.cc b/src/core/jsonschema/frame.cc index 699e13d26..eacc15cc9 100644 --- a/src/core/jsonschema/frame.cc +++ b/src/core/jsonschema/frame.cc @@ -262,7 +262,7 @@ auto internal_analyse(const sourcemeta::core::JSON &schema, // Schema identifier std::optional id{sourcemeta::core::identify( - entry.value, entry.base_dialect.value(), + entry.subschema.get(), entry.base_dialect.value(), entry.pointer.empty() ? default_id : std::nullopt)}; // Store information @@ -278,7 +278,7 @@ auto internal_analyse(const sourcemeta::core::JSON &schema, supports_id_anchors(entry.common.base_dialect.value()) && sourcemeta::core::URI{entry.id.value()}.is_fragment_only(); - if ((!entry.common.value.defines("$ref") || !ref_overrides) && + if ((!entry.common.subschema.get().defines("$ref") || !ref_overrides) && // If we are dealing with a pre-2019-09 location independent // identifier, we ignore it as a traditional identifier and take care // of it as an anchor @@ -323,7 +323,8 @@ auto internal_analyse(const sourcemeta::core::JSON &schema, } // Handle metaschema references - const auto maybe_metaschema{sourcemeta::core::dialect(entry.common.value)}; + const auto maybe_metaschema{ + sourcemeta::core::dialect(entry.common.subschema.get())}; if (maybe_metaschema.has_value()) { sourcemeta::core::URI metaschema{maybe_metaschema.value()}; const auto nearest_bases{ @@ -334,7 +335,7 @@ auto internal_analyse(const sourcemeta::core::JSON &schema, metaschema.canonicalize(); const std::string destination{metaschema.recompose()}; - assert(entry.common.value.defines("$schema")); + assert(entry.common.subschema.get().defines("$schema")); references.insert_or_assign( {SchemaReferenceType::Static, entry.common.pointer.concat({"$schema"})}, @@ -344,8 +345,8 @@ auto internal_analyse(const sourcemeta::core::JSON &schema, } // Handle schema anchors - for (const auto &[name, type] : - find_anchors(entry.common.value, entry.common.vocabularies)) { + for (const auto &[name, type] : find_anchors(entry.common.subschema.get(), + entry.common.vocabularies)) { const auto bases{ find_nearest_bases(base_uris, entry.common.pointer, entry.id)}; @@ -490,12 +491,13 @@ auto internal_analyse(const sourcemeta::core::JSON &schema, // Resolve references after all framing was performed for (const auto &entry : subschema_entries) { - if (entry.common.value.is_object()) { + if (entry.common.subschema.get().is_object()) { const auto nearest_bases{ find_nearest_bases(base_uris, entry.common.pointer, entry.id)}; - if (entry.common.value.defines("$ref")) { - assert(entry.common.value.at("$ref").is_string()); - sourcemeta::core::URI ref{entry.common.value.at("$ref").to_string()}; + if (entry.common.subschema.get().defines("$ref")) { + assert(entry.common.subschema.get().at("$ref").is_string()); + sourcemeta::core::URI ref{ + entry.common.subschema.get().at("$ref").to_string()}; if (!nearest_bases.first.empty()) { ref.try_resolve_from(nearest_bases.first.front()); } @@ -511,9 +513,10 @@ auto internal_analyse(const sourcemeta::core::JSON &schema, if (entry.common.vocabularies.contains( "https://json-schema.org/draft/2019-09/vocab/core") && - entry.common.value.defines("$recursiveRef")) { - assert(entry.common.value.at("$recursiveRef").is_string()); - const auto &ref{entry.common.value.at("$recursiveRef").to_string()}; + entry.common.subschema.get().defines("$recursiveRef")) { + assert(entry.common.subschema.get().at("$recursiveRef").is_string()); + const auto &ref{ + entry.common.subschema.get().at("$recursiveRef").to_string()}; // The behavior of this keyword is defined only for the value "#". // Implementations MAY choose to consider other values to be errors. @@ -542,10 +545,10 @@ auto internal_analyse(const sourcemeta::core::JSON &schema, if (entry.common.vocabularies.contains( "https://json-schema.org/draft/2020-12/vocab/core") && - entry.common.value.defines("$dynamicRef")) { - assert(entry.common.value.at("$dynamicRef").is_string()); + entry.common.subschema.get().defines("$dynamicRef")) { + assert(entry.common.subschema.get().at("$dynamicRef").is_string()); sourcemeta::core::URI ref{ - entry.common.value.at("$dynamicRef").to_string()}; + entry.common.subschema.get().at("$dynamicRef").to_string()}; if (!nearest_bases.first.empty()) { ref.resolve_from(nearest_bases.first.front()); } diff --git a/src/core/jsonschema/include/sourcemeta/core/jsonschema_types.h b/src/core/jsonschema/include/sourcemeta/core/jsonschema_types.h index e190b02b4..b42a8edf6 100644 --- a/src/core/jsonschema/include/sourcemeta/core/jsonschema_types.h +++ b/src/core/jsonschema/include/sourcemeta/core/jsonschema_types.h @@ -2,7 +2,7 @@ #define SOURCEMETA_CORE_JSONSCHEMA_TYPES_H_ #include // std::uint8_t -#include // std::function +#include // std::function, std::reference_wrapper #include // std::map #include // std::optional #include // std::set @@ -193,9 +193,7 @@ struct SchemaIteratorEntry { std::optional dialect; std::map vocabularies; std::optional base_dialect; - // TODO: Do we really need a full copy of the JSON value if the client - // can get it through the JSON Pointer if needed? - JSON value; + std::reference_wrapper subschema; PointerTemplate relative_instance_location; bool orphan; }; diff --git a/src/core/jsonschema/walker.cc b/src/core/jsonschema/walker.cc index c8d014f59..bfef93f91 100644 --- a/src/core/jsonschema/walker.cc +++ b/src/core/jsonschema/walker.cc @@ -34,8 +34,10 @@ auto walk(const sourcemeta::core::Pointer &pointer, resolver, base_dialect.value(), new_dialect)}; if (type == SchemaWalkerType_t::Deep || level > 0) { - subschemas.push_back({pointer, new_dialect, vocabularies, base_dialect, - subschema, instance_location, orphan}); + sourcemeta::core::SchemaIteratorEntry entry{ + pointer, new_dialect, vocabularies, base_dialect, + subschema, instance_location, orphan}; + subschemas.push_back(std::move(entry)); } // We can't recurse any further @@ -265,13 +267,10 @@ sourcemeta::core::SchemaIterator::SchemaIterator( // not pass a default, then there is nothing we can do. We know // the current schema is a subschema, but cannot walk any further. if (!dialect.has_value()) { - this->subschemas.push_back({pointer, - std::nullopt, - {}, - std::nullopt, - schema, - instance_location, - false}); + sourcemeta::core::SchemaIteratorEntry entry{ + pointer, std::nullopt, {}, std::nullopt, + schema, instance_location, false}; + this->subschemas.push_back(std::move(entry)); } else { walk(pointer, instance_location, this->subschemas, schema, walker, resolver, dialect.value(), SchemaWalkerType_t::Deep, 0, false); @@ -315,13 +314,10 @@ sourcemeta::core::SchemaKeywordIterator::SchemaKeywordIterator( } for (const auto &entry : schema.as_object()) { - this->entries.push_back({{entry.first}, - dialect, - vocabularies, - base_dialect, - entry.second, - {}, - false}); + sourcemeta::core::SchemaIteratorEntry subschema_entry{ + {entry.first}, dialect, vocabularies, base_dialect, + entry.second, {}, false}; + this->entries.push_back(std::move(subschema_entry)); } // Sort keywords based on priority for correct evaluation diff --git a/test/jsonschema/jsonschema_keyword_iterator_test.cc b/test/jsonschema/jsonschema_keyword_iterator_test.cc index 2459a5391..6b118d437 100644 --- a/test/jsonschema/jsonschema_keyword_iterator_test.cc +++ b/test/jsonschema/jsonschema_keyword_iterator_test.cc @@ -43,57 +43,58 @@ TEST(JSONSchema_keyword_iterator, draft_2020_12) { EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); EXPECT_EQ( - entries.at(0).value, + entries.at(0).subschema.get(), sourcemeta::core::JSON{"https://json-schema.org/draft/2020-12/schema"}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"if"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"maxContains"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::JSON{1}); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::JSON{1}); EXPECT_EQ(entries.at(3).pointer, sourcemeta::core::Pointer({"minContains"})); - EXPECT_EQ(entries.at(3).value, sourcemeta::core::JSON{0}); + EXPECT_EQ(entries.at(3).subschema.get(), sourcemeta::core::JSON{0}); EXPECT_EQ(entries.at(4).pointer, sourcemeta::core::Pointer({"patternProperties"})); - EXPECT_EQ(entries.at(4).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(4).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(5).pointer, sourcemeta::core::Pointer({"prefixItems"})); - EXPECT_EQ(entries.at(5).value, sourcemeta::core::parse_json("[]")); + EXPECT_EQ(entries.at(5).subschema.get(), sourcemeta::core::parse_json("[]")); EXPECT_EQ(entries.at(6).pointer, sourcemeta::core::Pointer({"required"})); - EXPECT_EQ(entries.at(6).value, sourcemeta::core::parse_json("[ \"foo\" ]")); + EXPECT_EQ(entries.at(6).subschema.get(), + sourcemeta::core::parse_json("[ \"foo\" ]")); EXPECT_EQ(entries.at(7).pointer, sourcemeta::core::Pointer({"contains"})); - EXPECT_EQ(entries.at(7).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(7).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(8).pointer, sourcemeta::core::Pointer({"else"})); - EXPECT_EQ(entries.at(8).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(8).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(9).pointer, sourcemeta::core::Pointer({"items"})); - EXPECT_EQ(entries.at(9).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(9).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(10).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(10).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(10).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(11).pointer, sourcemeta::core::Pointer({"then"})); - EXPECT_EQ(entries.at(11).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(11).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(12).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(12).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(12).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(13).pointer, sourcemeta::core::Pointer({"type"})); - EXPECT_EQ(entries.at(13).value, sourcemeta::core::JSON{"string"}); + EXPECT_EQ(entries.at(13).subschema.get(), sourcemeta::core::JSON{"string"}); EXPECT_EQ(entries.at(14).pointer, sourcemeta::core::Pointer({"unevaluatedItems"})); - EXPECT_EQ(entries.at(14).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(14).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(15).pointer, sourcemeta::core::Pointer({"unevaluatedProperties"})); - EXPECT_EQ(entries.at(15).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(15).subschema.get(), sourcemeta::core::JSON{true}); } TEST(JSONSchema_keyword_iterator, draft_2019_09) { @@ -133,58 +134,59 @@ TEST(JSONSchema_keyword_iterator, draft_2019_09) { EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); EXPECT_EQ( - entries.at(0).value, + entries.at(0).subschema.get(), sourcemeta::core::JSON{"https://json-schema.org/draft/2019-09/schema"}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"if"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"items"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::parse_json("[]")); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::parse_json("[]")); EXPECT_EQ(entries.at(3).pointer, sourcemeta::core::Pointer({"maxContains"})); - EXPECT_EQ(entries.at(3).value, sourcemeta::core::JSON{1}); + EXPECT_EQ(entries.at(3).subschema.get(), sourcemeta::core::JSON{1}); EXPECT_EQ(entries.at(4).pointer, sourcemeta::core::Pointer({"minContains"})); - EXPECT_EQ(entries.at(4).value, sourcemeta::core::JSON{0}); + EXPECT_EQ(entries.at(4).subschema.get(), sourcemeta::core::JSON{0}); EXPECT_EQ(entries.at(5).pointer, sourcemeta::core::Pointer({"patternProperties"})); - EXPECT_EQ(entries.at(5).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(5).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(6).pointer, sourcemeta::core::Pointer({"required"})); - EXPECT_EQ(entries.at(6).value, sourcemeta::core::parse_json("[ \"foo\" ]")); + EXPECT_EQ(entries.at(6).subschema.get(), + sourcemeta::core::parse_json("[ \"foo\" ]")); EXPECT_EQ(entries.at(7).pointer, sourcemeta::core::Pointer({"additionalItems"})); - EXPECT_EQ(entries.at(7).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(7).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(8).pointer, sourcemeta::core::Pointer({"contains"})); - EXPECT_EQ(entries.at(8).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(8).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(9).pointer, sourcemeta::core::Pointer({"else"})); - EXPECT_EQ(entries.at(9).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(9).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(10).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(10).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(10).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(11).pointer, sourcemeta::core::Pointer({"then"})); - EXPECT_EQ(entries.at(11).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(11).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(12).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(12).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(12).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(13).pointer, sourcemeta::core::Pointer({"type"})); - EXPECT_EQ(entries.at(13).value, sourcemeta::core::JSON{"string"}); + EXPECT_EQ(entries.at(13).subschema.get(), sourcemeta::core::JSON{"string"}); EXPECT_EQ(entries.at(14).pointer, sourcemeta::core::Pointer({"unevaluatedItems"})); - EXPECT_EQ(entries.at(14).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(14).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(15).pointer, sourcemeta::core::Pointer({"unevaluatedProperties"})); - EXPECT_EQ(entries.at(15).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(15).subschema.get(), sourcemeta::core::JSON{true}); } TEST(JSONSchema_keyword_iterator, draft7) { @@ -217,41 +219,42 @@ TEST(JSONSchema_keyword_iterator, draft7) { EXPECT_EQ(entries.size(), 11); EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); - EXPECT_EQ(entries.at(0).value, + EXPECT_EQ(entries.at(0).subschema.get(), sourcemeta::core::JSON{"http://json-schema.org/draft-07/schema#"}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"if"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"items"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::parse_json("[]")); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::parse_json("[]")); EXPECT_EQ(entries.at(3).pointer, sourcemeta::core::Pointer({"patternProperties"})); - EXPECT_EQ(entries.at(3).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(3).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(4).pointer, sourcemeta::core::Pointer({"required"})); - EXPECT_EQ(entries.at(4).value, sourcemeta::core::parse_json("[ \"foo\" ]")); + EXPECT_EQ(entries.at(4).subschema.get(), + sourcemeta::core::parse_json("[ \"foo\" ]")); EXPECT_EQ(entries.at(5).pointer, sourcemeta::core::Pointer({"additionalItems"})); - EXPECT_EQ(entries.at(5).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(5).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(6).pointer, sourcemeta::core::Pointer({"else"})); - EXPECT_EQ(entries.at(6).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(6).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(7).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(7).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(7).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(8).pointer, sourcemeta::core::Pointer({"then"})); - EXPECT_EQ(entries.at(8).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(8).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(9).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(9).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(9).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(10).pointer, sourcemeta::core::Pointer({"type"})); - EXPECT_EQ(entries.at(10).value, sourcemeta::core::JSON{"string"}); + EXPECT_EQ(entries.at(10).subschema.get(), sourcemeta::core::JSON{"string"}); } TEST(JSONSchema_keyword_iterator, draft6) { @@ -281,32 +284,33 @@ TEST(JSONSchema_keyword_iterator, draft6) { EXPECT_EQ(entries.size(), 8); EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); - EXPECT_EQ(entries.at(0).value, + EXPECT_EQ(entries.at(0).subschema.get(), sourcemeta::core::JSON{"http://json-schema.org/draft-06/schema#"}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"items"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::parse_json("[]")); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::parse_json("[]")); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"patternProperties"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(3).pointer, sourcemeta::core::Pointer({"required"})); - EXPECT_EQ(entries.at(3).value, sourcemeta::core::parse_json("[ \"foo\" ]")); + EXPECT_EQ(entries.at(3).subschema.get(), + sourcemeta::core::parse_json("[ \"foo\" ]")); EXPECT_EQ(entries.at(4).pointer, sourcemeta::core::Pointer({"additionalItems"})); - EXPECT_EQ(entries.at(4).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(4).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(5).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(5).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(5).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(6).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(6).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(6).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(7).pointer, sourcemeta::core::Pointer({"type"})); - EXPECT_EQ(entries.at(7).value, sourcemeta::core::JSON{"string"}); + EXPECT_EQ(entries.at(7).subschema.get(), sourcemeta::core::JSON{"string"}); } TEST(JSONSchema_keyword_iterator, draft4) { @@ -336,32 +340,33 @@ TEST(JSONSchema_keyword_iterator, draft4) { EXPECT_EQ(entries.size(), 8); EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); - EXPECT_EQ(entries.at(0).value, + EXPECT_EQ(entries.at(0).subschema.get(), sourcemeta::core::JSON{"http://json-schema.org/draft-04/schema#"}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"items"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::parse_json("[]")); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::parse_json("[]")); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"patternProperties"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(3).pointer, sourcemeta::core::Pointer({"required"})); - EXPECT_EQ(entries.at(3).value, sourcemeta::core::parse_json("[ \"foo\" ]")); + EXPECT_EQ(entries.at(3).subschema.get(), + sourcemeta::core::parse_json("[ \"foo\" ]")); EXPECT_EQ(entries.at(4).pointer, sourcemeta::core::Pointer({"additionalItems"})); - EXPECT_EQ(entries.at(4).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(4).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(5).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(5).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(5).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(6).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(6).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(6).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(7).pointer, sourcemeta::core::Pointer({"type"})); - EXPECT_EQ(entries.at(7).value, sourcemeta::core::JSON{"string"}); + EXPECT_EQ(entries.at(7).subschema.get(), sourcemeta::core::JSON{"string"}); } TEST(JSONSchema_keyword_iterator, draft3) { @@ -390,29 +395,29 @@ TEST(JSONSchema_keyword_iterator, draft3) { EXPECT_EQ(entries.size(), 7); EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); - EXPECT_EQ(entries.at(0).value, + EXPECT_EQ(entries.at(0).subschema.get(), sourcemeta::core::JSON{"http://json-schema.org/draft-03/schema#"}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"items"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::parse_json("[]")); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::parse_json("[]")); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"patternProperties"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(3).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(3).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(3).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(4).pointer, sourcemeta::core::Pointer({"type"})); - EXPECT_EQ(entries.at(4).value, sourcemeta::core::JSON{"string"}); + EXPECT_EQ(entries.at(4).subschema.get(), sourcemeta::core::JSON{"string"}); EXPECT_EQ(entries.at(5).pointer, sourcemeta::core::Pointer({"additionalItems"})); - EXPECT_EQ(entries.at(5).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(5).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(6).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(6).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(6).subschema.get(), sourcemeta::core::JSON{true}); } TEST(JSONSchema_keyword_iterator, draft2) { @@ -439,18 +444,18 @@ TEST(JSONSchema_keyword_iterator, draft2) { EXPECT_EQ(entries.size(), 4); EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); - EXPECT_EQ(entries.at(0).value, + EXPECT_EQ(entries.at(0).subschema.get(), sourcemeta::core::JSON{"http://json-schema.org/draft-02/schema#"}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"type"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::JSON{"string"}); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::JSON{"string"}); EXPECT_EQ(entries.at(3).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(3).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(3).subschema.get(), sourcemeta::core::JSON{true}); } TEST(JSONSchema_keyword_iterator, draft1) { @@ -477,18 +482,18 @@ TEST(JSONSchema_keyword_iterator, draft1) { EXPECT_EQ(entries.size(), 4); EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); - EXPECT_EQ(entries.at(0).value, + EXPECT_EQ(entries.at(0).subschema.get(), sourcemeta::core::JSON{"http://json-schema.org/draft-01/schema#"}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"type"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::JSON{"string"}); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::JSON{"string"}); EXPECT_EQ(entries.at(3).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(3).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(3).subschema.get(), sourcemeta::core::JSON{true}); } TEST(JSONSchema_keyword_iterator, draft0) { @@ -515,18 +520,18 @@ TEST(JSONSchema_keyword_iterator, draft0) { EXPECT_EQ(entries.size(), 4); EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); - EXPECT_EQ(entries.at(0).value, + EXPECT_EQ(entries.at(0).subschema.get(), sourcemeta::core::JSON{"http://json-schema.org/draft-00/schema#"}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"type"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::JSON{"string"}); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::JSON{"string"}); EXPECT_EQ(entries.at(3).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(3).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(3).subschema.get(), sourcemeta::core::JSON{true}); } TEST(JSONSchema_keyword_iterator, unknown_keyword) { @@ -546,7 +551,7 @@ TEST(JSONSchema_keyword_iterator, unknown_keyword) { EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"$schema"})); EXPECT_EQ( - entries.at(0).value, + entries.at(0).subschema.get(), sourcemeta::core::JSON{"https://json-schema.org/draft/2020-12/schema"}); EXPECT_EQ(entries.at(0).dialect, "https://json-schema.org/draft/2020-12/schema"); @@ -555,7 +560,7 @@ TEST(JSONSchema_keyword_iterator, unknown_keyword) { EXPECT_EQ(entries.at(0).vocabularies.size(), 7); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"foobar"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::JSON{0}); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::JSON{0}); EXPECT_EQ(entries.at(1).dialect, "https://json-schema.org/draft/2020-12/schema"); EXPECT_EQ(entries.at(1).base_dialect, @@ -588,14 +593,14 @@ TEST(JSONSchema_keyword_iterator, with_default_dialect) { EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"patternProperties"})); - EXPECT_EQ(entries.at(0).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(0).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::JSON{true}); } TEST(JSONSchema_keyword_iterator, no_default_dialect) { @@ -621,14 +626,14 @@ TEST(JSONSchema_keyword_iterator, no_default_dialect) { EXPECT_EQ(entries.at(0).pointer, sourcemeta::core::Pointer({"additionalProperties"})); - EXPECT_EQ(entries.at(0).value, sourcemeta::core::JSON{true}); + EXPECT_EQ(entries.at(0).subschema.get(), sourcemeta::core::JSON{true}); EXPECT_EQ(entries.at(1).pointer, sourcemeta::core::Pointer({"patternProperties"})); - EXPECT_EQ(entries.at(1).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(1).subschema.get(), sourcemeta::core::parse_json("{}")); EXPECT_EQ(entries.at(2).pointer, sourcemeta::core::Pointer({"properties"})); - EXPECT_EQ(entries.at(2).value, sourcemeta::core::parse_json("{}")); + EXPECT_EQ(entries.at(2).subschema.get(), sourcemeta::core::parse_json("{}")); } TEST(JSONSchema_keyword_iterator, boolean_true) {