Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions test/jose/jose_jwk_private_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,59 @@ TEST(jwk_private_from_octets) {
EXPECT_FALSE(key.algorithm().has_value());
EXPECT_FALSE(key.public_jwk().has_value());
}

TEST(jwk_private_from_json_rejects_unknown_key_type) {
EXPECT_FALSE(sourcemeta::core::JWKPrivate::from(
sourcemeta::core::parse_json(R"({"kty":"XYZ","d":"abc"})"))
.has_value());
}

TEST(jwk_private_from_json_rejects_missing_key_type) {
EXPECT_FALSE(sourcemeta::core::JWKPrivate::from(
sourcemeta::core::parse_json(R"({"crv":"P-256","d":"abc"})"))
.has_value());
}

TEST(jwk_private_from_json_rejects_non_string_key_type) {
EXPECT_FALSE(sourcemeta::core::JWKPrivate::from(
sourcemeta::core::parse_json(R"({"kty":42})"))
.has_value());
}

TEST(jwk_private_from_json_rejects_rsa_multi_prime) {
EXPECT_FALSE(sourcemeta::core::JWKPrivate::from(
sourcemeta::core::parse_json(
R"({"kty":"RSA","n":"n","e":"AQAB","d":"d","p":"p",)"
R"("q":"q","dp":"dp","dq":"dq","qi":"qi","oth":[]})"))
.has_value());
}

TEST(jwk_private_from_json_rejects_rsa_missing_component) {
EXPECT_FALSE(sourcemeta::core::JWKPrivate::from(
sourcemeta::core::parse_json(
R"({"kty":"RSA","n":"n","e":"AQAB","d":"d","p":"p",)"
R"("q":"q","dp":"dp","dq":"dq"})"))
.has_value());
}

TEST(jwk_private_from_json_rejects_rsa_with_invalid_base64url) {
EXPECT_FALSE(sourcemeta::core::JWKPrivate::from(
sourcemeta::core::parse_json(
R"({"kty":"RSA","n":"!!!","e":"AQAB","d":"d","p":"p",)"
R"("q":"q","dp":"dp","dq":"dq","qi":"qi"})"))
.has_value());
}

TEST(jwk_private_from_json_rejects_ec_unknown_curve) {
EXPECT_FALSE(sourcemeta::core::JWKPrivate::from(
sourcemeta::core::parse_json(
R"({"kty":"EC","crv":"P-999","x":"x","y":"y","d":"d"})"))
.has_value());
}

TEST(jwk_private_from_json_rejects_okp_unknown_curve) {
EXPECT_FALSE(sourcemeta::core::JWKPrivate::from(
sourcemeta::core::parse_json(
R"({"kty":"OKP","crv":"X25519","x":"x","d":"d"})"))
.has_value());
}
113 changes: 113 additions & 0 deletions test/json/json_object_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1677,3 +1677,116 @@ TEST(unique_keys_true_long_keys) {
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa2": 2 })")};
EXPECT_TRUE(document.unique_keys());
}

TEST(long_key_collision_const_at) {
// A perfect hash covers keys up to thirty one bytes, so two keys sharing
// their first thirty one bytes, length, and end bytes collide and force the
// linear scan path
const std::string prefix(31, 'x');
const std::string first_key{prefix + "ay"};
const std::string second_key{prefix + "by"};
sourcemeta::core::JSON document = sourcemeta::core::JSON::make_object();
document.assign(first_key, sourcemeta::core::JSON{1});
document.assign(second_key, sourcemeta::core::JSON{2});
const auto &constant{document};
EXPECT_EQ(constant.at(first_key).to_integer(), 1);
EXPECT_EQ(constant.at(second_key).to_integer(), 2);
}

TEST(long_key_collision_mutable_at) {
// A perfect hash covers keys up to thirty one bytes, so two keys sharing
// their first thirty one bytes, length, and end bytes collide and force the
// linear scan path
const std::string prefix(31, 'x');
const std::string first_key{prefix + "ay"};
const std::string second_key{prefix + "by"};
sourcemeta::core::JSON document = sourcemeta::core::JSON::make_object();
document.assign(first_key, sourcemeta::core::JSON{1});
document.assign(second_key, sourcemeta::core::JSON{2});
document.at(second_key) = sourcemeta::core::JSON{9};
EXPECT_EQ(document.at(first_key).to_integer(), 1);
EXPECT_EQ(document.at(second_key).to_integer(), 9);
}

TEST(long_key_collision_try_at) {
// A perfect hash covers keys up to thirty one bytes, so two keys sharing
// their first thirty one bytes, length, and end bytes collide and force the
// linear scan path
const std::string prefix(31, 'x');
const std::string first_key{prefix + "ay"};
const std::string second_key{prefix + "by"};
sourcemeta::core::JSON document = sourcemeta::core::JSON::make_object();
document.assign(first_key, sourcemeta::core::JSON{1});
document.assign(second_key, sourcemeta::core::JSON{2});
EXPECT_TRUE(document.try_at(first_key) != nullptr);
EXPECT_EQ(document.try_at(first_key)->to_integer(), 1);
EXPECT_TRUE(document.try_at(second_key) != nullptr);
EXPECT_EQ(document.try_at(second_key)->to_integer(), 2);
const std::string absent{std::string(31, 'x') + "cy"};
EXPECT_EQ(document.try_at(absent), nullptr);
}

TEST(long_key_collision_defines) {
// A perfect hash covers keys up to thirty one bytes, so two keys sharing
// their first thirty one bytes, length, and end bytes collide and force the
// linear scan path
const std::string prefix(31, 'x');
const std::string first_key{prefix + "ay"};
const std::string second_key{prefix + "by"};
sourcemeta::core::JSON document = sourcemeta::core::JSON::make_object();
document.assign(first_key, sourcemeta::core::JSON{1});
EXPECT_TRUE(document.defines(first_key));
EXPECT_FALSE(document.defines(second_key));
}

TEST(long_key_collision_erase) {
// A perfect hash covers keys up to thirty one bytes, so two keys sharing
// their first thirty one bytes, length, and end bytes collide and force the
// linear scan path
const std::string prefix(31, 'x');
const std::string first_key{prefix + "ay"};
const std::string second_key{prefix + "by"};
sourcemeta::core::JSON document = sourcemeta::core::JSON::make_object();
document.assign(first_key, sourcemeta::core::JSON{1});
document.assign(second_key, sourcemeta::core::JSON{2});
document.erase(first_key);
EXPECT_EQ(document.size(), 1);
EXPECT_FALSE(document.defines(first_key));
EXPECT_TRUE(document.defines(second_key));
EXPECT_EQ(document.at(second_key).to_integer(), 2);
}

TEST(long_key_collision_find) {
// A perfect hash covers keys up to thirty one bytes, so two keys sharing
// their first thirty one bytes, length, and end bytes collide and force the
// linear scan path
const std::string prefix(31, 'x');
const std::string first_key{prefix + "ay"};
const std::string second_key{prefix + "by"};
sourcemeta::core::JSON document = sourcemeta::core::JSON::make_object();
document.assign(first_key, sourcemeta::core::JSON{1});
document.assign(second_key, sourcemeta::core::JSON{2});
const auto &object{document.as_object()};
const auto first_iterator{object.find(first_key)};
EXPECT_TRUE(first_iterator != object.cend());
EXPECT_EQ(first_iterator->second.to_integer(), 1);
const auto second_iterator{object.find(second_key)};
EXPECT_TRUE(second_iterator != object.cend());
EXPECT_EQ(second_iterator->second.to_integer(), 2);
}

TEST(long_key_collision_emplace_updates_existing) {
// A perfect hash covers keys up to thirty one bytes, so two keys sharing
// their first thirty one bytes, length, and end bytes collide and force the
// linear scan path
const std::string prefix(31, 'x');
const std::string first_key{prefix + "ay"};
const std::string second_key{prefix + "by"};
sourcemeta::core::JSON document = sourcemeta::core::JSON::make_object();
document.assign(first_key, sourcemeta::core::JSON{1});
document.assign(second_key, sourcemeta::core::JSON{2});
document.assign(second_key, sourcemeta::core::JSON{7});
EXPECT_EQ(document.size(), 2);
EXPECT_EQ(document.at(first_key).to_integer(), 1);
EXPECT_EQ(document.at(second_key).to_integer(), 7);
}
45 changes: 45 additions & 0 deletions test/jsonld/jsonld_expand_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -517,3 +517,48 @@ TEST(compact_iri_term_with_unresolvable_prefix) {
])JSON")};
EXPECT_EQ(result, expected);
}

TEST(type_redefinition_protected_with_matching_definition) {
const auto input = sourcemeta::core::parse_json(R"({
"@context": [
{ "@type": { "@container": "@set", "@protected": true } },
{ "@type": { "@container": "@set" } }
],
"@type": "http://example.com/T"
})");

const auto result{sourcemeta::core::jsonld_expand(input)};
const auto expected{sourcemeta::core::parse_json(R"([
{ "@type": [ "http://example.com/T" ] }
])")};
EXPECT_EQ(result, expected);
}

TEST(simple_term_with_keyword_form_is_dropped) {
const auto input = sourcemeta::core::parse_json(R"({
"@context": { "@vocab": "http://example.com/", "ignored": "@nest" },
"ignored": { "http://example.com/foo": "bar" }
})");

const auto result{sourcemeta::core::jsonld_expand(input)};
const auto expected{sourcemeta::core::parse_json(R"([
{ "http://example.com/foo": [ { "@value": "bar" } ] }
])")};
EXPECT_EQ(result, expected);
}

TEST(self_referential_compact_term_via_prefix) {
const auto input = sourcemeta::core::parse_json(R"({
"@context": {
"ex": "http://example.com/",
"ex:name": "ex:name"
},
"ex:name": "value"
})");

const auto result{sourcemeta::core::jsonld_expand(input)};
const auto expected{sourcemeta::core::parse_json(R"([
{ "http://example.com/name": [ { "@value": "value" } ] }
])")};
EXPECT_EQ(result, expected);
}
Loading
Loading