From c0e816c0058e758e62ec1ff1271eab5fe5173a02 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Thu, 9 Jan 2025 19:41:41 -0400 Subject: [PATCH] Extract `BundleOptions::WithoutIdentifiers` into its own `unidentify()` Signed-off-by: Juan Cruz Viotti --- src/jsonschema/CMakeLists.txt | 2 +- src/jsonschema/bundle.cc | 60 +- .../sourcemeta/jsontoolkit/jsonschema.h | 40 +- .../jsontoolkit/jsonschema_bundle.h | 16 - src/jsonschema/unidentify.cc | 49 ++ test/jsonschema/CMakeLists.txt | 1 + .../jsonschema_bundle_2019_09_test.cc | 84 -- .../jsonschema_bundle_2020_12_test.cc | 133 +--- .../jsonschema_bundle_draft4_test.cc | 68 -- .../jsonschema_bundle_draft6_test.cc | 68 -- .../jsonschema_bundle_draft7_test.cc | 68 -- test/jsonschema/jsonschema_bundle_test.cc | 1 - test/jsonschema/jsonschema_unidentify_test.cc | 749 ++++++++++++++++++ 13 files changed, 851 insertions(+), 488 deletions(-) create mode 100644 src/jsonschema/unidentify.cc create mode 100644 test/jsonschema/jsonschema_unidentify_test.cc diff --git a/src/jsonschema/CMakeLists.txt b/src/jsonschema/CMakeLists.txt index 068c9aa09..be29a4c55 100644 --- a/src/jsonschema/CMakeLists.txt +++ b/src/jsonschema/CMakeLists.txt @@ -8,7 +8,7 @@ noa_library(NAMESPACE sourcemeta PROJECT jsontoolkit NAME jsonschema walker.h reference.h frame.h error.h unevaluated.h keywords.h SOURCES jsonschema.cc default_walker.cc frame.cc anchor.cc resolver.cc walker.cc bundle.cc - unevaluated.cc relativize.cc + unevaluated.cc relativize.cc unidentify.cc "${CMAKE_CURRENT_BINARY_DIR}/official_resolver.cc") if(JSONTOOLKIT_INSTALL) diff --git a/src/jsonschema/bundle.cc b/src/jsonschema/bundle.cc index 5bc12878c..d160ec5d0 100644 --- a/src/jsonschema/bundle.cc +++ b/src/jsonschema/bundle.cc @@ -127,82 +127,26 @@ auto bundle_schema(sourcemeta::jsontoolkit::JSON &root, } } -auto remove_identifiers(sourcemeta::jsontoolkit::JSON &schema, - const sourcemeta::jsontoolkit::SchemaWalker &walker, - const sourcemeta::jsontoolkit::SchemaResolver &resolver, - const std::optional &default_dialect) - -> void { - // (1) Re-frame before changing anything - sourcemeta::jsontoolkit::Frame frame; - frame.analyse(schema, walker, resolver, default_dialect); - - // (2) Remove all identifiers and anchors - for (const auto &entry : sourcemeta::jsontoolkit::SchemaIterator{ - schema, walker, resolver, default_dialect}) { - auto &subschema{sourcemeta::jsontoolkit::get(schema, entry.pointer)}; - if (subschema.is_boolean()) { - continue; - } - - assert(entry.base_dialect.has_value()); - sourcemeta::jsontoolkit::anonymize(subschema, entry.base_dialect.value()); - - if (entry.vocabularies.contains( - "https://json-schema.org/draft/2020-12/vocab/core")) { - subschema.erase("$anchor"); - subschema.erase("$dynamicAnchor"); - } - - if (entry.vocabularies.contains( - "https://json-schema.org/draft/2019-09/vocab/core")) { - subschema.erase("$anchor"); - subschema.erase("$recursiveAnchor"); - } - } - - // (3) Fix-up reference based on pointers from the root - for (const auto &[key, reference] : frame.references()) { - // We don't want to bundle official schemas, as we can expect - // virtually all implementations to understand them out of the box - if (is_official_metaschema_reference(key.second, reference.destination)) { - continue; - } - - const auto result{frame.traverse(reference.destination)}; - assert(result.has_value()); - sourcemeta::jsontoolkit::set( - schema, key.second, - sourcemeta::jsontoolkit::JSON{ - sourcemeta::jsontoolkit::to_uri(result.value().get().pointer) - .recompose()}); - } -} - } // namespace namespace sourcemeta::jsontoolkit { auto bundle(sourcemeta::jsontoolkit::JSON &schema, const SchemaWalker &walker, - const SchemaResolver &resolver, const BundleOptions options, + const SchemaResolver &resolver, const std::optional &default_dialect) -> void { const auto vocabularies{ sourcemeta::jsontoolkit::vocabularies(schema, resolver, default_dialect)}; sourcemeta::jsontoolkit::Frame frame; bundle_schema(schema, definitions_keyword(vocabularies), schema, frame, walker, resolver, default_dialect); - - if (options == BundleOptions::WithoutIdentifiers) { - remove_identifiers(schema, walker, resolver, default_dialect); - } } auto bundle(const sourcemeta::jsontoolkit::JSON &schema, const SchemaWalker &walker, const SchemaResolver &resolver, - const BundleOptions options, const std::optional &default_dialect) -> sourcemeta::jsontoolkit::JSON { sourcemeta::jsontoolkit::JSON copy = schema; - bundle(copy, walker, resolver, options, default_dialect); + bundle(copy, walker, resolver, default_dialect); return copy; } diff --git a/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema.h b/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema.h index a3fd5f3e8..222e7f347 100644 --- a/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema.h +++ b/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema.h @@ -332,7 +332,7 @@ auto schema_format_compare(const JSON::String &left, const JSON::String &right) /// #include /// #include /// -/// sourcemeta::jsontoolkit::JSON document = +/// sourcemeta::jsontoolkit::JSON schema = /// sourcemeta::jsontoolkit::parse(R"JSON({ /// "$id": "https://www.example.com/schema", /// "$schema": "https://json-schema.org/draft/2020-12/schema", @@ -340,7 +340,7 @@ auto schema_format_compare(const JSON::String &left, const JSON::String &right) /// })JSON"); /// /// sourcemeta::jsontoolkit::relativize(schema, -/// sourcemeta::jsontoolkit::default_dialect, +/// sourcemeta::jsontoolkit::default_walker, /// sourcemeta::jsontoolkit::official_resolver); /// /// const sourcemeta::jsontoolkit::JSON expected = @@ -350,7 +350,7 @@ auto schema_format_compare(const JSON::String &left, const JSON::String &right) /// "$ref": "another", /// })JSON"); /// -/// assert(document == expected); +/// assert(schema == expected); /// ``` SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT auto relativize( @@ -358,6 +358,40 @@ auto relativize( const std::optional &default_dialect = std::nullopt, const std::optional &default_id = std::nullopt) -> void; +/// @ingroup jsonschema +/// +/// Remove every identifer from a schema, rephrasing references (if any) as +/// needed. For example: +/// +/// ```cpp +/// #include +/// #include +/// #include +/// +/// sourcemeta::jsontoolkit::JSON schema = +/// sourcemeta::jsontoolkit::parse(R"JSON({ +/// "$id": "https://www.example.com/schema", +/// "$schema": "https://json-schema.org/draft/2020-12/schema", +/// "$ref": "another", +/// })JSON"); +/// +/// sourcemeta::jsontoolkit::unidentify(schema, +/// sourcemeta::jsontoolkit::default_walker, +/// sourcemeta::jsontoolkit::official_resolver); +/// +/// const sourcemeta::jsontoolkit::JSON expected = +/// sourcemeta::jsontoolkit::parse(R"JSON({ +/// "$schema": "https://json-schema.org/draft/2020-12/schema", +/// "$ref": "https://www.example.com/another", +/// })JSON"); +/// +/// assert(schema == expected); +/// ``` +SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT +auto unidentify( + JSON &schema, const SchemaWalker &walker, const SchemaResolver &resolver, + const std::optional &default_dialect = std::nullopt) -> void; + } // namespace sourcemeta::jsontoolkit #endif diff --git a/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_bundle.h b/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_bundle.h index 345510bc8..334f7f516 100644 --- a/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_bundle.h +++ b/src/jsonschema/include/sourcemeta/jsontoolkit/jsonschema_bundle.h @@ -17,20 +17,6 @@ namespace sourcemeta::jsontoolkit { // TODO: Optionally let users bundle the metaschema too -/// @ingroup jsonschema -/// A set of options that modify the behavior of bundling -enum class BundleOptions : std::uint8_t { - /// Perform standard JSON Schema bundling - Default, - - /// Perform standard JSON Schema bundling but without making - /// use of identifiers. This is helpful for delivering - /// schemas to some non-compliant implementations that do not - /// recognize identifiers (like Visua Studio Code at the time - /// of this writing) - WithoutIdentifiers -}; - /// @ingroup jsonschema /// /// This function bundles a JSON Schema (starting from Draft 4) by embedding @@ -83,7 +69,6 @@ enum class BundleOptions : std::uint8_t { SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT auto bundle(sourcemeta::jsontoolkit::JSON &schema, const SchemaWalker &walker, const SchemaResolver &resolver, - const BundleOptions options = BundleOptions::Default, const std::optional &default_dialect = std::nullopt) -> void; @@ -141,7 +126,6 @@ auto bundle(sourcemeta::jsontoolkit::JSON &schema, const SchemaWalker &walker, SOURCEMETA_JSONTOOLKIT_JSONSCHEMA_EXPORT auto bundle(const sourcemeta::jsontoolkit::JSON &schema, const SchemaWalker &walker, const SchemaResolver &resolver, - const BundleOptions options = BundleOptions::Default, const std::optional &default_dialect = std::nullopt) -> sourcemeta::jsontoolkit::JSON; diff --git a/src/jsonschema/unidentify.cc b/src/jsonschema/unidentify.cc new file mode 100644 index 000000000..58f7c37a9 --- /dev/null +++ b/src/jsonschema/unidentify.cc @@ -0,0 +1,49 @@ +#include + +namespace sourcemeta::jsontoolkit { + +auto unidentify(JSON &schema, const SchemaWalker &walker, + const SchemaResolver &resolver, + const std::optional &default_dialect) -> void { + // (1) Re-frame before changing anything + Frame frame; + frame.analyse(schema, walker, resolver, default_dialect); + + // (2) Remove all identifiers and anchors + for (const auto &entry : + SchemaIterator{schema, walker, resolver, default_dialect}) { + auto &subschema{get(schema, entry.pointer)}; + if (subschema.is_boolean()) { + continue; + } + + assert(entry.base_dialect.has_value()); + anonymize(subschema, entry.base_dialect.value()); + + if (entry.vocabularies.contains( + "https://json-schema.org/draft/2020-12/vocab/core")) { + subschema.erase("$anchor"); + subschema.erase("$dynamicAnchor"); + } + + if (entry.vocabularies.contains( + "https://json-schema.org/draft/2019-09/vocab/core")) { + subschema.erase("$anchor"); + subschema.erase("$recursiveAnchor"); + } + } + + // (3) Fix-up reference based on pointers from the root + for (const auto &[key, reference] : frame.references()) { + const auto result{frame.traverse(reference.destination)}; + if (result.has_value()) { + set(schema, key.second, + JSON{to_uri(result.value().get().pointer).recompose()}); + } else if (!key.second.empty() && key.second.back().is_property() && + key.second.back().to_property() != "$schema") { + set(schema, key.second, JSON{reference.destination}); + } + } +} + +} // namespace sourcemeta::jsontoolkit diff --git a/test/jsonschema/CMakeLists.txt b/test/jsonschema/CMakeLists.txt index c36e83754..9d29bac2c 100644 --- a/test/jsonschema/CMakeLists.txt +++ b/test/jsonschema/CMakeLists.txt @@ -38,6 +38,7 @@ add_executable(sourcemeta_jsontoolkit_jsonschema_unit jsonschema_bundle_draft1_test.cc jsonschema_bundle_draft0_test.cc jsonschema_bundle_test.cc + jsonschema_unidentify_test.cc jsonschema_metaschema_test.cc jsonschema_dialect_test.cc jsonschema_dialect_2020_12_test.cc diff --git a/test/jsonschema/jsonschema_bundle_2019_09_test.cc b/test/jsonschema/jsonschema_bundle_2019_09_test.cc index 59e2ce8b5..41a51277c 100644 --- a/test/jsonschema/jsonschema_bundle_2019_09_test.cc +++ b/test/jsonschema/jsonschema_bundle_2019_09_test.cc @@ -449,7 +449,6 @@ TEST(JSONSchema_bundle_2019_09, anonymous_no_dialect) { sourcemeta::jsontoolkit::bundle( document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::Default, "https://json-schema.org/draft/2019-09/schema"); const sourcemeta::jsontoolkit::JSON expected = @@ -466,59 +465,6 @@ TEST(JSONSchema_bundle_2019_09, anonymous_no_dialect) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_2019_09, without_id) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$id": "https://www.sourcemeta.com/top-level", - "$schema": "https://json-schema.org/draft/2019-09/schema", - "properties": { - "foo": { - "$ref": "recursive#/properties/foo" - }, - "baz": { - "$ref": "https://example.com/baz-anchor#baz" - } - } - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "properties": { - "foo": { - "$ref": "#/$defs/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" - }, - "baz": { - "$ref": "#/$defs/https%3A~1~1example.com~1baz-anchor/$defs/baz" - } - }, - "$defs": { - "https://www.sourcemeta.com/recursive": { - "$schema": "https://json-schema.org/draft/2019-09/schema", - "properties": { - "foo": { - "$ref": "#/$defs/https%3A~1~1www.sourcemeta.com~1recursive" - } - } - }, - "https://example.com/baz-anchor": { - "$schema": "https://json-schema.org/draft/2019-09/schema", - "$defs": { - "baz": { - "type": "string" - } - } - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} - TEST(JSONSchema_bundle_2019_09, metaschema) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ @@ -550,36 +496,6 @@ TEST(JSONSchema_bundle_2019_09, metaschema) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_2019_09, metaschema_without_id) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "https://example.com/meta/1.json", - "type": "string" - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "#/$defs/https%3A~1~1example.com~1meta~11.json", - "type": "string", - "$defs": { - "https://example.com/meta/1.json": { - "$schema": "#/$defs/https%3A~1~1example.com~1meta~12.json", - "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true } - }, - "https://example.com/meta/2.json": { - "$schema": "https://json-schema.org/draft/2019-09/schema", - "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true } - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} - TEST(JSONSchema_bundle_2019_09, relative_base_uri_with_ref) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ diff --git a/test/jsonschema/jsonschema_bundle_2020_12_test.cc b/test/jsonschema/jsonschema_bundle_2020_12_test.cc index 1dd6ca5d6..3dbf2d1e2 100644 --- a/test/jsonschema/jsonschema_bundle_2020_12_test.cc +++ b/test/jsonschema/jsonschema_bundle_2020_12_test.cc @@ -489,7 +489,6 @@ TEST(JSONSchema_bundle_2020_12, anonymous_no_dialect) { sourcemeta::jsontoolkit::bundle( document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::Default, "https://json-schema.org/draft/2020-12/schema"); const sourcemeta::jsontoolkit::JSON expected = @@ -539,52 +538,30 @@ TEST(JSONSchema_bundle_2020_12, relative_in_target_without_id) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_2020_12, without_id) { +TEST(JSONSchema_bundle_2020_12, relative_base_uri_with_ref) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ - "$id": "https://www.sourcemeta.com/top-level", "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { - "$ref": "recursive#/properties/foo" - }, - "baz": { - "$ref": "https://example.com/baz-anchor#baz" + "$id": "common", + "allOf": [ { "$ref": "#reference" } ], + "definitions": { + "reference": { + "$anchor": "reference" } } })JSON"); sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); + document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver); const sourcemeta::jsontoolkit::JSON expected = sourcemeta::jsontoolkit::parse(R"JSON({ "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { - "$ref": "#/$defs/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" - }, - "baz": { - "$ref": "#/$defs/https%3A~1~1example.com~1baz-anchor/$defs/baz" - } - }, - "$defs": { - "https://www.sourcemeta.com/recursive": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { - "$ref": "#/$defs/https%3A~1~1www.sourcemeta.com~1recursive" - } - } - }, - "https://example.com/baz-anchor": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "baz": { - "type": "string" - } - } + "$id": "common", + "allOf": [ { "$ref": "#reference" } ], + "definitions": { + "reference": { + "$anchor": "reference" } } })JSON"); @@ -592,31 +569,6 @@ TEST(JSONSchema_bundle_2020_12, without_id) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_2020_12, without_id_boolean_subschema) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$id": "https://www.sourcemeta.com/top-level", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": true - } - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": true - } - })JSON"); - - EXPECT_EQ(document, expected); -} - TEST(JSONSchema_bundle_2020_12, metaschema) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ @@ -647,64 +599,3 @@ TEST(JSONSchema_bundle_2020_12, metaschema) { EXPECT_EQ(document, expected); } - -TEST(JSONSchema_bundle_2020_12, metaschema_without_id) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "https://example.com/meta/1.json", - "type": "string" - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "#/$defs/https%3A~1~1example.com~1meta~11.json", - "type": "string", - "$defs": { - "https://example.com/meta/1.json": { - "$schema": "#/$defs/https%3A~1~1example.com~1meta~12.json", - "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true } - }, - "https://example.com/meta/2.json": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true } - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} - -TEST(JSONSchema_bundle_2020_12, relative_base_uri_with_ref) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "common", - "allOf": [ { "$ref": "#reference" } ], - "definitions": { - "reference": { - "$anchor": "reference" - } - } - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "common", - "allOf": [ { "$ref": "#reference" } ], - "definitions": { - "reference": { - "$anchor": "reference" - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} diff --git a/test/jsonschema/jsonschema_bundle_draft4_test.cc b/test/jsonschema/jsonschema_bundle_draft4_test.cc index 4abff8823..5dcb06a56 100644 --- a/test/jsonschema/jsonschema_bundle_draft4_test.cc +++ b/test/jsonschema/jsonschema_bundle_draft4_test.cc @@ -449,7 +449,6 @@ TEST(JSONSchema_bundle_draft4, anonymous_no_dialect) { sourcemeta::jsontoolkit::bundle( document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::Default, "http://json-schema.org/draft-04/schema#"); const sourcemeta::jsontoolkit::JSON expected = @@ -466,45 +465,6 @@ TEST(JSONSchema_bundle_draft4, anonymous_no_dialect) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_draft4, without_id) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "id": "https://www.sourcemeta.com/top-level", - "$schema": "http://json-schema.org/draft-04/schema#", - "properties": { - "foo": { - "$ref": "recursive#/properties/foo" - } - } - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "http://json-schema.org/draft-04/schema#", - "properties": { - "foo": { - "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" - } - }, - "definitions": { - "https://www.sourcemeta.com/recursive": { - "$schema": "http://json-schema.org/draft-04/schema#", - "properties": { - "foo": { - "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive" - } - } - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} - TEST(JSONSchema_bundle_draft4, metaschema) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ @@ -534,34 +494,6 @@ TEST(JSONSchema_bundle_draft4, metaschema) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_draft4, metaschema_without_id) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "https://example.com/meta/1.json", - "type": "string" - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "#/definitions/https%3A~1~1example.com~1meta~11.json", - "type": "string", - "definitions": { - "https://example.com/meta/1.json": { - "$schema": "#/definitions/https%3A~1~1example.com~1meta~12.json" - }, - "https://example.com/meta/2.json": { - "$schema": "http://json-schema.org/draft-04/schema#" - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} - TEST(JSONSchema_bundle_draft4, relative_base_uri_without_ref) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ diff --git a/test/jsonschema/jsonschema_bundle_draft6_test.cc b/test/jsonschema/jsonschema_bundle_draft6_test.cc index 26c40b61e..1754aea77 100644 --- a/test/jsonschema/jsonschema_bundle_draft6_test.cc +++ b/test/jsonschema/jsonschema_bundle_draft6_test.cc @@ -424,7 +424,6 @@ TEST(JSONSchema_bundle_draft6, anonymous_no_dialect) { sourcemeta::jsontoolkit::bundle( document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::Default, "http://json-schema.org/draft-06/schema#"); const sourcemeta::jsontoolkit::JSON expected = @@ -441,45 +440,6 @@ TEST(JSONSchema_bundle_draft6, anonymous_no_dialect) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_draft6, without_id) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$id": "https://www.sourcemeta.com/top-level", - "$schema": "http://json-schema.org/draft-06/schema#", - "properties": { - "foo": { - "$ref": "recursive#/properties/foo" - } - } - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "http://json-schema.org/draft-06/schema#", - "properties": { - "foo": { - "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" - } - }, - "definitions": { - "https://www.sourcemeta.com/recursive": { - "$schema": "http://json-schema.org/draft-06/schema#", - "properties": { - "foo": { - "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive" - } - } - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} - TEST(JSONSchema_bundle_draft6, metaschema) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ @@ -509,34 +469,6 @@ TEST(JSONSchema_bundle_draft6, metaschema) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_draft6, metaschema_without_id) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "https://example.com/meta/1.json", - "type": "string" - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "#/definitions/https%3A~1~1example.com~1meta~11.json", - "type": "string", - "definitions": { - "https://example.com/meta/1.json": { - "$schema": "#/definitions/https%3A~1~1example.com~1meta~12.json" - }, - "https://example.com/meta/2.json": { - "$schema": "http://json-schema.org/draft-06/schema#" - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} - TEST(JSONSchema_bundle_draft6, relative_base_uri_with_ref) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ diff --git a/test/jsonschema/jsonschema_bundle_draft7_test.cc b/test/jsonschema/jsonschema_bundle_draft7_test.cc index aadf779f6..5eafc807a 100644 --- a/test/jsonschema/jsonschema_bundle_draft7_test.cc +++ b/test/jsonschema/jsonschema_bundle_draft7_test.cc @@ -424,7 +424,6 @@ TEST(JSONSchema_bundle_draft7, anonymous_no_dialect) { sourcemeta::jsontoolkit::bundle( document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::Default, "http://json-schema.org/draft-07/schema#"); const sourcemeta::jsontoolkit::JSON expected = @@ -441,45 +440,6 @@ TEST(JSONSchema_bundle_draft7, anonymous_no_dialect) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_draft7, without_id) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$id": "https://www.sourcemeta.com/top-level", - "$schema": "http://json-schema.org/draft-07/schema#", - "properties": { - "foo": { - "$ref": "recursive#/properties/foo" - } - } - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "http://json-schema.org/draft-07/schema#", - "properties": { - "foo": { - "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" - } - }, - "definitions": { - "https://www.sourcemeta.com/recursive": { - "$schema": "http://json-schema.org/draft-07/schema#", - "properties": { - "foo": { - "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive" - } - } - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} - TEST(JSONSchema_bundle_draft7, metaschema) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ @@ -509,34 +469,6 @@ TEST(JSONSchema_bundle_draft7, metaschema) { EXPECT_EQ(document, expected); } -TEST(JSONSchema_bundle_draft7, metaschema_without_id) { - sourcemeta::jsontoolkit::JSON document = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "https://example.com/meta/1.json", - "type": "string" - })JSON"); - - sourcemeta::jsontoolkit::bundle( - document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers); - - const sourcemeta::jsontoolkit::JSON expected = - sourcemeta::jsontoolkit::parse(R"JSON({ - "$schema": "#/definitions/https%3A~1~1example.com~1meta~11.json", - "type": "string", - "definitions": { - "https://example.com/meta/1.json": { - "$schema": "#/definitions/https%3A~1~1example.com~1meta~12.json" - }, - "https://example.com/meta/2.json": { - "$schema": "http://json-schema.org/draft-07/schema#" - } - } - })JSON"); - - EXPECT_EQ(document, expected); -} - TEST(JSONSchema_bundle_draft7, relative_base_uri_with_ref) { sourcemeta::jsontoolkit::JSON document = sourcemeta::jsontoolkit::parse(R"JSON({ diff --git a/test/jsonschema/jsonschema_bundle_test.cc b/test/jsonschema/jsonschema_bundle_test.cc index 30344bb3c..046b4a661 100644 --- a/test/jsonschema/jsonschema_bundle_test.cc +++ b/test/jsonschema/jsonschema_bundle_test.cc @@ -131,7 +131,6 @@ TEST(JSONSchema_bundle, with_default_dialect) { sourcemeta::jsontoolkit::bundle( document, sourcemeta::jsontoolkit::default_schema_walker, test_resolver, - sourcemeta::jsontoolkit::BundleOptions::Default, "https://json-schema.org/draft/2020-12/schema"); const sourcemeta::jsontoolkit::JSON expected = diff --git a/test/jsonschema/jsonschema_unidentify_test.cc b/test/jsonschema/jsonschema_unidentify_test.cc new file mode 100644 index 000000000..997c53c65 --- /dev/null +++ b/test/jsonschema/jsonschema_unidentify_test.cc @@ -0,0 +1,749 @@ +#include + +#include +#include + +static auto test_resolver_2020_12(std::string_view identifier) + -> std::optional { + if (identifier == "https://example.com/foo/bar") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/foo/bar", + "$anchor": "baz" + })JSON"); + } else if (identifier == "https://example.com/baz-anchor") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/baz-anchor", + "$defs": { + "baz": { + "$anchor": "baz", + "type": "string" + } + } + })JSON"); + } else if (identifier == "https://www.sourcemeta.com/recursive") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://www.sourcemeta.com/recursive", + "properties": { + "foo": { "$ref": "#" } + } + })JSON"); + } else if (identifier == "https://example.com/meta/1.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/2.json", + "$id": "https://example.com/meta/1.json", + "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true } + })JSON"); + } else if (identifier == "https://example.com/meta/2.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/meta/2.json", + "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true } + })JSON"); + } else { + return sourcemeta::jsontoolkit::official_resolver(identifier); + } +} + +static auto test_resolver_2019_09(std::string_view identifier) + -> std::optional { + if (identifier == "https://example.com/foo/bar") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://example.com/foo/bar", + "$anchor": "baz" + })JSON"); + } else if (identifier == "https://example.com/baz-anchor") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://example.com/baz-anchor", + "$defs": { + "baz": { + "$anchor": "baz", + "type": "string" + } + } + })JSON"); + } else if (identifier == "https://www.sourcemeta.com/recursive") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://www.sourcemeta.com/recursive", + "properties": { + "foo": { "$ref": "#" } + } + })JSON"); + } else if (identifier == "https://example.com/meta/1.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/2.json", + "$id": "https://example.com/meta/1.json", + "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true } + })JSON"); + } else if (identifier == "https://example.com/meta/2.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$id": "https://example.com/meta/2.json", + "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true } + })JSON"); + } else { + return sourcemeta::jsontoolkit::official_resolver(identifier); + } +} + +static auto test_resolver_draft7(std::string_view identifier) + -> std::optional { + if (identifier == "https://www.sourcemeta.com/recursive") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://www.sourcemeta.com/recursive", + "properties": { + "foo": { "$ref": "#" } + } + })JSON"); + } else if (identifier == "https://example.com/meta/1.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/2.json", + "$id": "https://example.com/meta/1.json" + })JSON"); + } else if (identifier == "https://example.com/meta/2.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://example.com/meta/2.json" + })JSON"); + } else { + return sourcemeta::jsontoolkit::official_resolver(identifier); + } +} + +static auto test_resolver_draft6(std::string_view identifier) + -> std::optional { + if (identifier == "https://www.sourcemeta.com/recursive") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "$id": "https://www.sourcemeta.com/recursive", + "properties": { + "foo": { "$ref": "#" } + } + })JSON"); + } else if (identifier == "https://example.com/meta/1.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/2.json", + "$id": "https://example.com/meta/1.json" + })JSON"); + } else if (identifier == "https://example.com/meta/2.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "$id": "https://example.com/meta/2.json" + })JSON"); + } else { + return sourcemeta::jsontoolkit::official_resolver(identifier); + } +} + +static auto test_resolver_draft4(std::string_view identifier) + -> std::optional { + if (identifier == "https://www.sourcemeta.com/recursive") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "https://www.sourcemeta.com/recursive", + "properties": { + "foo": { "$ref": "#" } + } + })JSON"); + } else if (identifier == "https://example.com/meta/1.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/2.json", + "id": "https://example.com/meta/1.json" + })JSON"); + } else if (identifier == "https://example.com/meta/2.json") { + return sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "id": "https://example.com/meta/2.json" + })JSON"); + } else { + return sourcemeta::jsontoolkit::official_resolver(identifier); + } +} + +TEST(JSONSchema_unidentify, 2020_12) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/top-level", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + }, + "baz": { + "$ref": "https://example.com/baz-anchor#baz" + } + } + })JSON"); + + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2020_12); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "foo": { + "$ref": "https://www.sourcemeta.com/recursive#/properties/foo" + }, + "baz": { + "$ref": "https://example.com/baz-anchor#baz" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, 2020_12_bundle) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/top-level", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + }, + "baz": { + "$ref": "https://example.com/baz-anchor#baz" + } + } + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2020_12); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2020_12); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "foo": { + "$ref": "#/$defs/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" + }, + "baz": { + "$ref": "#/$defs/https%3A~1~1example.com~1baz-anchor/$defs/baz" + } + }, + "$defs": { + "https://www.sourcemeta.com/recursive": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "foo": { + "$ref": "#/$defs/https%3A~1~1www.sourcemeta.com~1recursive" + } + } + }, + "https://example.com/baz-anchor": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$defs": { + "baz": { + "type": "string" + } + } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, 2020_12_bundle_boolean_subschema) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/top-level", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "foo": true + } + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2020_12); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2020_12); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "properties": { + "foo": true + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, 2020_12_bundle_metaschema) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/1.json", + "type": "string" + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2020_12); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2020_12); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "#/$defs/https%3A~1~1example.com~1meta~11.json", + "type": "string", + "$defs": { + "https://example.com/meta/1.json": { + "$schema": "#/$defs/https%3A~1~1example.com~1meta~12.json", + "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true } + }, + "https://example.com/meta/2.json": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$vocabulary": { "https://json-schema.org/draft/2020-12/vocab/core": true } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, 2019_09) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/top-level", + "$schema": "https://json-schema.org/draft/2019-09/schema", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + }, + "baz": { + "$ref": "https://example.com/baz-anchor#baz" + } + } + })JSON"); + + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2019_09); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "properties": { + "foo": { + "$ref": "https://www.sourcemeta.com/recursive#/properties/foo" + }, + "baz": { + "$ref": "https://example.com/baz-anchor#baz" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, 2019_09_bundle) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/top-level", + "$schema": "https://json-schema.org/draft/2019-09/schema", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + }, + "baz": { + "$ref": "https://example.com/baz-anchor#baz" + } + } + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2019_09); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2019_09); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://json-schema.org/draft/2019-09/schema", + "properties": { + "foo": { + "$ref": "#/$defs/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" + }, + "baz": { + "$ref": "#/$defs/https%3A~1~1example.com~1baz-anchor/$defs/baz" + } + }, + "$defs": { + "https://www.sourcemeta.com/recursive": { + "$schema": "https://json-schema.org/draft/2019-09/schema", + "properties": { + "foo": { + "$ref": "#/$defs/https%3A~1~1www.sourcemeta.com~1recursive" + } + } + }, + "https://example.com/baz-anchor": { + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$defs": { + "baz": { + "type": "string" + } + } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, 2019_09_bundle_metaschema) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/1.json", + "type": "string" + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2019_09); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_2019_09); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "#/$defs/https%3A~1~1example.com~1meta~11.json", + "type": "string", + "$defs": { + "https://example.com/meta/1.json": { + "$schema": "#/$defs/https%3A~1~1example.com~1meta~12.json", + "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true } + }, + "https://example.com/meta/2.json": { + "$schema": "https://json-schema.org/draft/2019-09/schema", + "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, draft7) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/top-level", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + } + } + })JSON"); + + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft7); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "foo": { + "$ref": "https://www.sourcemeta.com/recursive#/properties/foo" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, draft7_bundle) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/top-level", + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + } + } + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft7); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft7); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "foo": { + "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" + } + }, + "definitions": { + "https://www.sourcemeta.com/recursive": { + "$schema": "http://json-schema.org/draft-07/schema#", + "properties": { + "foo": { + "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive" + } + } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, draft7_bundle_metaschema) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/1.json", + "type": "string" + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft7); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft7); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "#/definitions/https%3A~1~1example.com~1meta~11.json", + "type": "string", + "definitions": { + "https://example.com/meta/1.json": { + "$schema": "#/definitions/https%3A~1~1example.com~1meta~12.json" + }, + "https://example.com/meta/2.json": { + "$schema": "http://json-schema.org/draft-07/schema#" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, draft6) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/top-level", + "$schema": "http://json-schema.org/draft-06/schema#", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + } + } + })JSON"); + + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft6); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "properties": { + "foo": { + "$ref": "https://www.sourcemeta.com/recursive#/properties/foo" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, draft6_bundle) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$id": "https://www.sourcemeta.com/top-level", + "$schema": "http://json-schema.org/draft-06/schema#", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + } + } + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft6); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft6); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-06/schema#", + "properties": { + "foo": { + "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" + } + }, + "definitions": { + "https://www.sourcemeta.com/recursive": { + "$schema": "http://json-schema.org/draft-06/schema#", + "properties": { + "foo": { + "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive" + } + } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, draft6_bundle_metaschema) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/1.json", + "type": "string" + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft6); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft6); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "#/definitions/https%3A~1~1example.com~1meta~11.json", + "type": "string", + "definitions": { + "https://example.com/meta/1.json": { + "$schema": "#/definitions/https%3A~1~1example.com~1meta~12.json" + }, + "https://example.com/meta/2.json": { + "$schema": "http://json-schema.org/draft-06/schema#" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, draft4) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "id": "https://www.sourcemeta.com/top-level", + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + } + } + })JSON"); + + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft4); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": { + "foo": { + "$ref": "https://www.sourcemeta.com/recursive#/properties/foo" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, draft4_bundle) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "id": "https://www.sourcemeta.com/top-level", + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": { + "foo": { + "$ref": "recursive#/properties/foo" + } + } + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft4); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft4); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": { + "foo": { + "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive/properties/foo" + } + }, + "definitions": { + "https://www.sourcemeta.com/recursive": { + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": { + "foo": { + "$ref": "#/definitions/https%3A~1~1www.sourcemeta.com~1recursive" + } + } + } + } + })JSON"); + + EXPECT_EQ(document, expected); +} + +TEST(JSONSchema_unidentify, draft4_bundle_metaschema) { + sourcemeta::jsontoolkit::JSON document = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "https://example.com/meta/1.json", + "type": "string" + })JSON"); + + sourcemeta::jsontoolkit::bundle( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft4); + sourcemeta::jsontoolkit::unidentify( + document, sourcemeta::jsontoolkit::default_schema_walker, + test_resolver_draft4); + + const sourcemeta::jsontoolkit::JSON expected = + sourcemeta::jsontoolkit::parse(R"JSON({ + "$schema": "#/definitions/https%3A~1~1example.com~1meta~11.json", + "type": "string", + "definitions": { + "https://example.com/meta/1.json": { + "$schema": "#/definitions/https%3A~1~1example.com~1meta~12.json" + }, + "https://example.com/meta/2.json": { + "$schema": "http://json-schema.org/draft-04/schema#" + } + } + })JSON"); + + EXPECT_EQ(document, expected); +}