Skip to content

Commit

Permalink
Make sure identifiers are canonicalised during framing
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <[email protected]>
  • Loading branch information
jviotti committed Jan 31, 2025
1 parent 0204113 commit 12d8698
Show file tree
Hide file tree
Showing 12 changed files with 347 additions and 3 deletions.
8 changes: 6 additions & 2 deletions src/core/jsonschema/frame.cc
Original file line number Diff line number Diff line change
Expand Up @@ -226,8 +226,12 @@ auto internal_analyse(const sourcemeta::core::JSON &schema,
throw SchemaError("Cannot determine the base dialect of the schema");
}

const std::optional<std::string> root_id{sourcemeta::core::identify(
std::optional<std::string> root_id{sourcemeta::core::identify(
schema, root_base_dialect.value(), default_id)};
if (root_id.has_value()) {
root_id = URI{root_id.value()}.canonicalize().recompose();
}

const std::optional<std::string> root_dialect{
sourcemeta::core::dialect(schema, default_dialect)};
assert(root_dialect.has_value());
Expand Down Expand Up @@ -296,7 +300,7 @@ auto internal_analyse(const sourcemeta::core::JSON &schema,
}

const bool maybe_relative_is_absolute{maybe_relative.is_absolute()};
maybe_relative.try_resolve_from(base);
maybe_relative.try_resolve_from(base).canonicalize();
const std::string new_id{maybe_relative.recompose()};

if (!maybe_relative_is_absolute ||
Expand Down
6 changes: 5 additions & 1 deletion src/core/uri/uri.cc
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,11 @@ auto URI::canonicalize() -> URI & {
if (result_path.has_value()) {
const auto canonical_path{canonicalize_path(result_path.value())};
if (canonical_path.has_value()) {
this->path_ = canonical_path.value();
if (result_path.value().ends_with('/')) {
this->path_ = canonical_path.value() + "/";
} else {
this->path_ = canonical_path.value();
}
}
}

Expand Down
36 changes: 36 additions & 0 deletions test/jsonschema/jsonschema_frame_2019_09_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,42 @@ TEST(JSONSchema_frame_2019_09, empty_schema) {
"https://json-schema.org/draft/2019-09/schema", std::nullopt);
}

TEST(JSONSchema_frame_2019_09, empty_schema_trailing_hash) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$id": "https://www.sourcemeta.com/schema#",
"$schema": "https://json-schema.org/draft/2019-09/schema"
})JSON");

sourcemeta::core::SchemaFrame frame;
frame.analyse(document, sourcemeta::core::schema_official_walker,
sourcemeta::core::schema_official_resolver);

EXPECT_EQ(frame.locations().size(), 3);
EXPECT_FRAME_STATIC_2019_09_RESOURCE(
frame, "https://www.sourcemeta.com/schema",
"https://www.sourcemeta.com/schema", "",
"https://www.sourcemeta.com/schema", "", 0);

// JSON Pointers

EXPECT_FRAME_STATIC_2019_09_POINTER(
frame, "https://www.sourcemeta.com/schema#/$id",
"https://www.sourcemeta.com/schema", "/$id",
"https://www.sourcemeta.com/schema", "/$id", 0);
EXPECT_FRAME_STATIC_2019_09_POINTER(
frame, "https://www.sourcemeta.com/schema#/$schema",
"https://www.sourcemeta.com/schema", "/$schema",
"https://www.sourcemeta.com/schema", "/$schema", 0);

// References

EXPECT_EQ(frame.references().size(), 1);

EXPECT_STATIC_REFERENCE(
frame, "/$schema", "https://json-schema.org/draft/2019-09/schema",
"https://json-schema.org/draft/2019-09/schema", std::nullopt);
}

TEST(JSONSchema_frame_2019_09, one_level_applicators_without_identifiers) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$id": "https://www.sourcemeta.com/schema",
Expand Down
36 changes: 36 additions & 0 deletions test/jsonschema/jsonschema_frame_2020_12_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,42 @@ TEST(JSONSchema_frame_2020_12, empty_schema) {
"https://json-schema.org/draft/2020-12/schema", std::nullopt);
}

TEST(JSONSchema_frame_2020_12, empty_schema_trailing_hash) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$id": "https://www.sourcemeta.com/schema#",
"$schema": "https://json-schema.org/draft/2020-12/schema"
})JSON");

sourcemeta::core::SchemaFrame frame;
frame.analyse(document, sourcemeta::core::schema_official_walker,
sourcemeta::core::schema_official_resolver);

EXPECT_EQ(frame.locations().size(), 3);
EXPECT_FRAME_STATIC_2020_12_RESOURCE(
frame, "https://www.sourcemeta.com/schema",
"https://www.sourcemeta.com/schema", "",
"https://www.sourcemeta.com/schema", "", 0);

// JSON Pointers

EXPECT_FRAME_STATIC_2020_12_POINTER(
frame, "https://www.sourcemeta.com/schema#/$id",
"https://www.sourcemeta.com/schema", "/$id",
"https://www.sourcemeta.com/schema", "/$id", 0);
EXPECT_FRAME_STATIC_2020_12_POINTER(
frame, "https://www.sourcemeta.com/schema#/$schema",
"https://www.sourcemeta.com/schema", "/$schema",
"https://www.sourcemeta.com/schema", "/$schema", 0);

// References

EXPECT_EQ(frame.references().size(), 1);

EXPECT_STATIC_REFERENCE(
frame, "/$schema", "https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2020-12/schema", std::nullopt);
}

TEST(JSONSchema_frame_2020_12, one_level_applicators_without_identifiers) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$id": "https://www.sourcemeta.com/schema",
Expand Down
36 changes: 36 additions & 0 deletions test/jsonschema/jsonschema_frame_draft0_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,42 @@ TEST(JSONSchema_frame_draft0, empty_schema) {
"http://json-schema.org/draft-00/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft0, empty_schema_trailing_hash) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema#",
"$schema": "http://json-schema.org/draft-00/schema#"
})JSON");

sourcemeta::core::SchemaFrame frame;
frame.analyse(document, sourcemeta::core::schema_official_walker,
sourcemeta::core::schema_official_resolver);

EXPECT_EQ(frame.locations().size(), 3);
EXPECT_FRAME_STATIC_DRAFT0_RESOURCE(
frame, "https://www.sourcemeta.com/schema",
"https://www.sourcemeta.com/schema", "",
"https://www.sourcemeta.com/schema", "", 0);

// JSON Pointers

EXPECT_FRAME_STATIC_DRAFT0_POINTER(
frame, "https://www.sourcemeta.com/schema#/id",
"https://www.sourcemeta.com/schema", "/id",
"https://www.sourcemeta.com/schema", "/id", 0);
EXPECT_FRAME_STATIC_DRAFT0_POINTER(
frame, "https://www.sourcemeta.com/schema#/$schema",
"https://www.sourcemeta.com/schema", "/$schema",
"https://www.sourcemeta.com/schema", "/$schema", 0);

// References

EXPECT_EQ(frame.references().size(), 1);

EXPECT_STATIC_REFERENCE(
frame, "/$schema", "http://json-schema.org/draft-00/schema",
"http://json-schema.org/draft-00/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft0, one_level_applicators_without_identifiers) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema",
Expand Down
36 changes: 36 additions & 0 deletions test/jsonschema/jsonschema_frame_draft1_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,42 @@ TEST(JSONSchema_frame_draft1, empty_schema) {
"http://json-schema.org/draft-01/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft1, empty_schema_trailing_hash) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema#",
"$schema": "http://json-schema.org/draft-01/schema#"
})JSON");

sourcemeta::core::SchemaFrame frame;
frame.analyse(document, sourcemeta::core::schema_official_walker,
sourcemeta::core::schema_official_resolver);

EXPECT_EQ(frame.locations().size(), 3);
EXPECT_FRAME_STATIC_DRAFT1_RESOURCE(
frame, "https://www.sourcemeta.com/schema",
"https://www.sourcemeta.com/schema", "",
"https://www.sourcemeta.com/schema", "", 0);

// JSON Pointers

EXPECT_FRAME_STATIC_DRAFT1_POINTER(
frame, "https://www.sourcemeta.com/schema#/id",
"https://www.sourcemeta.com/schema", "/id",
"https://www.sourcemeta.com/schema", "/id", 0);
EXPECT_FRAME_STATIC_DRAFT1_POINTER(
frame, "https://www.sourcemeta.com/schema#/$schema",
"https://www.sourcemeta.com/schema", "/$schema",
"https://www.sourcemeta.com/schema", "/$schema", 0);

// References

EXPECT_EQ(frame.references().size(), 1);

EXPECT_STATIC_REFERENCE(
frame, "/$schema", "http://json-schema.org/draft-01/schema",
"http://json-schema.org/draft-01/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft1, one_level_applicators_without_identifiers) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema",
Expand Down
36 changes: 36 additions & 0 deletions test/jsonschema/jsonschema_frame_draft2_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,42 @@ TEST(JSONSchema_frame_draft2, empty_schema) {
"http://json-schema.org/draft-02/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft2, empty_schema_trailing_hash) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema#",
"$schema": "http://json-schema.org/draft-02/schema#"
})JSON");

sourcemeta::core::SchemaFrame frame;
frame.analyse(document, sourcemeta::core::schema_official_walker,
sourcemeta::core::schema_official_resolver);

EXPECT_EQ(frame.locations().size(), 3);
EXPECT_FRAME_STATIC_DRAFT2_RESOURCE(
frame, "https://www.sourcemeta.com/schema",
"https://www.sourcemeta.com/schema", "",
"https://www.sourcemeta.com/schema", "", 0);

// JSON Pointers

EXPECT_FRAME_STATIC_DRAFT2_POINTER(
frame, "https://www.sourcemeta.com/schema#/id",
"https://www.sourcemeta.com/schema", "/id",
"https://www.sourcemeta.com/schema", "/id", 0);
EXPECT_FRAME_STATIC_DRAFT2_POINTER(
frame, "https://www.sourcemeta.com/schema#/$schema",
"https://www.sourcemeta.com/schema", "/$schema",
"https://www.sourcemeta.com/schema", "/$schema", 0);

// References

EXPECT_EQ(frame.references().size(), 1);

EXPECT_STATIC_REFERENCE(
frame, "/$schema", "http://json-schema.org/draft-02/schema",
"http://json-schema.org/draft-02/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft2, one_level_applicators_without_identifiers) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema",
Expand Down
36 changes: 36 additions & 0 deletions test/jsonschema/jsonschema_frame_draft3_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,42 @@ TEST(JSONSchema_frame_draft3, empty_schema) {
"http://json-schema.org/draft-03/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft3, empty_schema_trailing_slash) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema#",
"$schema": "http://json-schema.org/draft-03/schema#"
})JSON");

sourcemeta::core::SchemaFrame frame;
frame.analyse(document, sourcemeta::core::schema_official_walker,
sourcemeta::core::schema_official_resolver);

EXPECT_EQ(frame.locations().size(), 3);
EXPECT_FRAME_STATIC_DRAFT3_RESOURCE(
frame, "https://www.sourcemeta.com/schema",
"https://www.sourcemeta.com/schema", "",
"https://www.sourcemeta.com/schema", "", 0);

// JSON Pointers

EXPECT_FRAME_STATIC_DRAFT3_POINTER(
frame, "https://www.sourcemeta.com/schema#/id",
"https://www.sourcemeta.com/schema", "/id",
"https://www.sourcemeta.com/schema", "/id", 0);
EXPECT_FRAME_STATIC_DRAFT3_POINTER(
frame, "https://www.sourcemeta.com/schema#/$schema",
"https://www.sourcemeta.com/schema", "/$schema",
"https://www.sourcemeta.com/schema", "/$schema", 0);

// References

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);
}

TEST(JSONSchema_frame_draft3, one_level_applicators_without_identifiers) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema",
Expand Down
36 changes: 36 additions & 0 deletions test/jsonschema/jsonschema_frame_draft4_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,42 @@ TEST(JSONSchema_frame_draft4, empty_schema) {
"http://json-schema.org/draft-04/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft4, empty_schema_trailing_hash) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema#",
"$schema": "http://json-schema.org/draft-04/schema#"
})JSON");

sourcemeta::core::SchemaFrame frame;
frame.analyse(document, sourcemeta::core::schema_official_walker,
sourcemeta::core::schema_official_resolver);

EXPECT_EQ(frame.locations().size(), 3);
EXPECT_FRAME_STATIC_DRAFT4_RESOURCE(
frame, "https://www.sourcemeta.com/schema",
"https://www.sourcemeta.com/schema", "",
"https://www.sourcemeta.com/schema", "", 0);

// JSON Pointers

EXPECT_FRAME_STATIC_DRAFT4_POINTER(
frame, "https://www.sourcemeta.com/schema#/id",
"https://www.sourcemeta.com/schema", "/id",
"https://www.sourcemeta.com/schema", "/id", 0);
EXPECT_FRAME_STATIC_DRAFT4_POINTER(
frame, "https://www.sourcemeta.com/schema#/$schema",
"https://www.sourcemeta.com/schema", "/$schema",
"https://www.sourcemeta.com/schema", "/$schema", 0);

// References

EXPECT_EQ(frame.references().size(), 1);

EXPECT_STATIC_REFERENCE(
frame, "/$schema", "http://json-schema.org/draft-04/schema",
"http://json-schema.org/draft-04/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft4, one_level_applicators_without_identifiers) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"id": "https://www.sourcemeta.com/schema",
Expand Down
36 changes: 36 additions & 0 deletions test/jsonschema/jsonschema_frame_draft6_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,42 @@ TEST(JSONSchema_frame_draft6, empty_schema) {
"http://json-schema.org/draft-06/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft6, empty_schema_trailing_hash) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$id": "https://www.sourcemeta.com/schema#",
"$schema": "http://json-schema.org/draft-06/schema#"
})JSON");

sourcemeta::core::SchemaFrame frame;
frame.analyse(document, sourcemeta::core::schema_official_walker,
sourcemeta::core::schema_official_resolver);

EXPECT_EQ(frame.locations().size(), 3);
EXPECT_FRAME_STATIC_DRAFT6_RESOURCE(
frame, "https://www.sourcemeta.com/schema",
"https://www.sourcemeta.com/schema", "",
"https://www.sourcemeta.com/schema", "", 0);

// JSON Pointers

EXPECT_FRAME_STATIC_DRAFT6_POINTER(
frame, "https://www.sourcemeta.com/schema#/$id",
"https://www.sourcemeta.com/schema", "/$id",
"https://www.sourcemeta.com/schema", "/$id", 0);
EXPECT_FRAME_STATIC_DRAFT6_POINTER(
frame, "https://www.sourcemeta.com/schema#/$schema",
"https://www.sourcemeta.com/schema", "/$schema",
"https://www.sourcemeta.com/schema", "/$schema", 0);

// References

EXPECT_EQ(frame.references().size(), 1);

EXPECT_STATIC_REFERENCE(
frame, "/$schema", "http://json-schema.org/draft-06/schema",
"http://json-schema.org/draft-06/schema", std::nullopt);
}

TEST(JSONSchema_frame_draft6, one_level_applicators_without_identifiers) {
const sourcemeta::core::JSON document = sourcemeta::core::parse_json(R"JSON({
"$id": "https://www.sourcemeta.com/schema",
Expand Down
Loading

0 comments on commit 12d8698

Please sign in to comment.