From d30c243751b8a4c6ebd73c6195f41bfe51c0ceaa Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 7 Aug 2026 16:53:01 -0300 Subject: [PATCH 1/6] Add even more coverage guided unit tests Signed-off-by: Juan Cruz Viotti --- test/ip/ipv6_classify_test.cc | 15 + test/ip/ipv6_test.cc | 12 + test/json/json_auto_test.cc | 97 ++++++ test/json/json_value_test.cc | 73 +++++ test/jsonld/jsonld_expand_test.cc | 90 ++++++ test/jsonld/jsonld_is_expanded_test.cc | 129 ++++++++ test/jsonpath/jsonpath_filter_test.cc | 36 +++ test/jsonpath/jsonpath_parse_test.cc | 22 +- test/jsonpointer/jsonpointer_pointer_test.cc | 26 ++ test/oauth/oauth_dpop_test.cc | 10 + test/oauth/oauth_metadata_test.cc | 42 +++ test/oauth/oauth_resource_metadata_test.cc | 22 ++ test/oidc/oidc_authentication_test.cc | 39 +++ test/oidc/oidc_discovery_test.cc | 71 +++++ test/oidc/oidc_registration_test.cc | 76 +++++ test/regex/regex_rfc9485_matches_test.cc | 73 +++++ test/regex/regex_to_regex_test.cc | 12 + test/time/imf_fixdate_test.cc | 120 ++++++++ test/uri/uri_parse_test.cc | 22 ++ test/uri/uri_path_test.cc | 70 +++++ test/uri/uri_relative_to_test.cc | 25 ++ .../uritemplate_parse_error_test.cc | 4 + test/yaml/yaml_parse_test.cc | 277 +++++++++++++++++- test/yaml/yaml_stringify_test.cc | 63 ++++ 24 files changed, 1422 insertions(+), 4 deletions(-) diff --git a/test/ip/ipv6_classify_test.cc b/test/ip/ipv6_classify_test.cc index 822e9629ea..6756e23ac1 100644 --- a/test/ip/ipv6_classify_test.cc +++ b/test/ip/ipv6_classify_test.cc @@ -241,3 +241,18 @@ TEST(invalid_empty) { TEST(invalid_ipv4) { EXPECT_FALSE(sourcemeta::core::ipv6_classify("127.0.0.1").has_value()); } + +TEST(teredo_prefix_nonzero_middle_not_anycast) { + const auto result{sourcemeta::core::ipv6_classify("2001:1:0:0:0:0:100:1")}; + EXPECT_EQ(result.value(), sourcemeta::core::IPAddressClass::Reserved); +} + +TEST(benchmarking_prefix_last_byte_above_three) { + const auto result{sourcemeta::core::ipv6_classify("2001:1::4")}; + EXPECT_EQ(result.value(), sourcemeta::core::IPAddressClass::Reserved); +} + +TEST(leading_zero_but_not_mapped_form) { + const auto result{sourcemeta::core::ipv6_classify("::100:0:0")}; + EXPECT_EQ(result.value(), sourcemeta::core::IPAddressClass::Reserved); +} diff --git a/test/ip/ipv6_test.cc b/test/ip/ipv6_test.cc index dcbcb97689..99b5491308 100644 --- a/test/ip/ipv6_test.cc +++ b/test/ip/ipv6_test.cc @@ -355,3 +355,15 @@ TEST(valid_two_digit_hex_groups_with_leading_zeros) { TEST(valid_three_digit_hex_groups_with_leading_zeros) { EXPECT_TRUE(sourcemeta::core::is_ipv6("001:002:003:004:005:006:007:008")); } + +TEST(rejects_trailing_bracket) { + EXPECT_FALSE(sourcemeta::core::is_ipv6("1::]")); +} + +TEST(rejects_leading_single_colon_with_double) { + EXPECT_FALSE(sourcemeta::core::is_ipv6(":1::2")); +} + +TEST(rejects_trailing_single_colon_with_double) { + EXPECT_FALSE(sourcemeta::core::is_ipv6("1::2:")); +} diff --git a/test/json/json_auto_test.cc b/test/json/json_auto_test.cc index 091cd88081..576730af6c 100644 --- a/test/json/json_auto_test.cc +++ b/test/json/json_auto_test.cc @@ -1189,3 +1189,100 @@ TEST(to_json_string_view_subview) { EXPECT_TRUE(result.is_string()); EXPECT_EQ(result.to_string(), "hello"); } + +TEST(from_json_optional_null_returns_nullopt_inner) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("null"))}; + EXPECT_TRUE(result.has_value()); + EXPECT_FALSE(result.value().has_value()); +} + +TEST(from_json_vector_element_mismatch_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("[1]"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_vector_non_array_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("5"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_map_value_mismatch_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json(R"({ "a": 1 })"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_map_non_object_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("5"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_pair_non_array_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("5"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_pair_wrong_size_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("[1]"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_pair_first_mismatch_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("[1, 2]"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_single_tuple_non_array_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("5"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_single_tuple_wrong_size_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("[1, 2]"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_tuple_non_array_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("5"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_tuple_wrong_size_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("[1]"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_variant_non_array_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("5"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_variant_wrong_size_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("[0]"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_variant_non_integer_index_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json(R"([ "x", 1 ])"))}; + EXPECT_FALSE(result.has_value()); +} + +TEST(from_json_variant_index_out_of_range_fails) { + const auto result{sourcemeta::core::from_json>( + sourcemeta::core::parse_json("[ 5, 0 ]"))}; + EXPECT_FALSE(result.has_value()); +} diff --git a/test/json/json_value_test.cc b/test/json/json_value_test.cc index 99ed5df7a8..0a6bddf252 100644 --- a/test/json/json_value_test.cc +++ b/test/json/json_value_test.cc @@ -841,3 +841,76 @@ TEST(deep_copy_of_a_nested_object) { EXPECT_EQ(copy, document); EXPECT_EQ(copy.at(0).at("a").at("b").at(1).to_integer(), 2); } + +TEST(add_integer_overflow_promotes_to_decimal) { + const sourcemeta::core::JSON left{std::numeric_limits::min()}; + const sourcemeta::core::JSON right{-1}; + // The integer sum overflows int64, so the operator promotes to Decimal. + // The promoted result is currently rounded to the decimal working precision + // rather than exact (tracked in the decimal precision bug report), so this + // asserts only that the overflow branch is taken + const auto result{left + right}; + EXPECT_TRUE(result.is_decimal()); +} + +TEST(subtract_integer_overflow_promotes_to_decimal) { + const sourcemeta::core::JSON left{std::numeric_limits::max()}; + const sourcemeta::core::JSON right{-1}; + // See the note on the addition overflow test above + const auto result{left - right}; + EXPECT_TRUE(result.is_decimal()); +} + +TEST(copy_self_assignment) { + sourcemeta::core::JSON value{42}; + const sourcemeta::core::JSON &alias{value}; + value = alias; + EXPECT_EQ(value.to_integer(), 42); +} + +TEST(move_self_assignment) { + sourcemeta::core::JSON value{42}; + // Route through a reference so the compiler cannot statically flag the + // self-move, while the runtime self-assignment branch is still exercised + sourcemeta::core::JSON &alias{value}; + value = std::move(alias); + EXPECT_EQ(value.to_integer(), 42); +} + +TEST(null_less_than_null_is_false) { + EXPECT_FALSE(sourcemeta::core::JSON{nullptr} < + sourcemeta::core::JSON{nullptr}); +} + +TEST(real_below_int64_range_throws_on_as_integer) { + const sourcemeta::core::JSON value{-1e300}; + try { + static_cast(value.as_integer()); + FAIL(); + } catch (...) { + } +} + +TEST(empty_on_string_returns_false) { + const sourcemeta::core::JSON value{"abc"}; + EXPECT_FALSE(value.empty()); +} + +TEST(fast_hash_of_real_below_int64_range) { + const sourcemeta::core::JSON value{-1e300}; + static_cast(value.fast_hash()); + EXPECT_TRUE(value.is_real()); +} + +TEST(fast_hash_of_real_above_int64_range) { + const sourcemeta::core::JSON value{1e300}; + static_cast(value.fast_hash()); + EXPECT_TRUE(value.is_real()); +} + +TEST(merge_object_key_over_non_object_source) { + auto target{sourcemeta::core::parse_json(R"JSON({ "k": { "x": 1 } })JSON")}; + const auto source{sourcemeta::core::parse_json(R"JSON({ "k": 2 })JSON")}; + target.merge(source.as_object()); + EXPECT_EQ(target.at("k").to_integer(), 2); +} diff --git a/test/jsonld/jsonld_expand_test.cc b/test/jsonld/jsonld_expand_test.cc index 763b67cba5..f2faba6972 100644 --- a/test/jsonld/jsonld_expand_test.cc +++ b/test/jsonld/jsonld_expand_test.cc @@ -562,3 +562,93 @@ TEST(self_referential_compact_term_via_prefix) { ])")}; EXPECT_EQ(result, expected); } + +TEST(type_array_with_non_string_item_is_rejected) { + const auto input = sourcemeta::core::parse_json(R"({ "@type": [ 123 ] })"); + try { + const auto result{sourcemeta::core::jsonld_expand(input)}; + FAIL(); + } catch (const sourcemeta::core::JSONLDError &) { + } +} + +TEST(top_level_non_string_direction_is_rejected) { + const auto input = sourcemeta::core::parse_json(R"({ "@direction": 123 })"); + try { + const auto result{sourcemeta::core::jsonld_expand(input)}; + FAIL(); + } catch (const sourcemeta::core::JSONLDError &) { + } +} + +TEST(nest_array_item_not_an_object_is_rejected) { + const auto input = sourcemeta::core::parse_json(R"({ + "@context": { "@vocab": "http://example.com/" }, + "@nest": [ "x" ] + })"); + try { + const auto result{sourcemeta::core::jsonld_expand(input)}; + FAIL(); + } catch (const sourcemeta::core::JSONLDError &) { + } +} + +TEST(nest_array_item_value_object_is_rejected) { + const auto input = sourcemeta::core::parse_json(R"({ + "@context": { "@vocab": "http://example.com/" }, + "@nest": [ { "@value": "x" } ] + })"); + try { + const auto result{sourcemeta::core::jsonld_expand(input)}; + FAIL(); + } catch (const sourcemeta::core::JSONLDError &) { + } +} + +TEST(term_container_array_with_non_string_is_rejected) { + const auto input = sourcemeta::core::parse_json(R"({ + "@context": { "t": { "@id": "http://ex/t", "@container": [ 123 ] } }, + "t": "x" + })"); + try { + const auto result{sourcemeta::core::jsonld_expand(input)}; + FAIL(); + } catch (const sourcemeta::core::JSONLDError &) { + } +} + +TEST(term_container_array_with_invalid_container_is_rejected) { + const auto input = sourcemeta::core::parse_json(R"({ + "@context": { "t": { "@id": "http://ex/t", "@container": [ "@bogus" ] } }, + "t": "x" + })"); + try { + const auto result{sourcemeta::core::jsonld_expand(input)}; + FAIL(); + } catch (const sourcemeta::core::JSONLDError &) { + } +} + +TEST(term_direction_non_string_is_rejected) { + const auto input = sourcemeta::core::parse_json(R"({ + "@context": { "t": { "@id": "http://ex/t", "@direction": 123 } }, + "t": "x" + })"); + try { + const auto result{sourcemeta::core::jsonld_expand(input)}; + FAIL(); + } catch (const sourcemeta::core::JSONLDError &) { + } +} + +TEST(term_nest_non_string_is_rejected) { + const auto input = sourcemeta::core::parse_json(R"({ + "@context": { "t": { "@id": "http://ex/t", "@nest": 123 } }, + "t": "x" + })"); + try { + const auto result{sourcemeta::core::jsonld_expand(input)}; + FAIL(); + } catch (const sourcemeta::core::JSONLDError &) { + } +} diff --git a/test/jsonld/jsonld_is_expanded_test.cc b/test/jsonld/jsonld_is_expanded_test.cc index b3c6961f82..ca2712ca9b 100644 --- a/test/jsonld/jsonld_is_expanded_test.cc +++ b/test/jsonld/jsonld_is_expanded_test.cc @@ -345,3 +345,132 @@ TEST(reverse_value_not_array) { ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } + +TEST(value_object_with_type_and_direction_no_language) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ + { "@value": "x", "@type": "http://example.com/t", "@direction": "ltr" } + ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_non_string_type) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@value": "x", "@type": 123 } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_non_iri_type) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@value": "x", "@type": "notaniri" } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_object_contents_and_type) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ + { "@value": { "a": 1 }, "@type": "http://example.com/t" } + ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_array_contents_and_type) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ + { "@value": [ 1, 2 ], "@type": "http://example.com/t" } + ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_array_contents_no_type) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@value": [ 1, 2 ] } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_non_string_language) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@value": "x", "@language": 123 } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_language_but_non_string_value) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@value": 123, "@language": "en" } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_non_string_direction) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@value": "x", "@direction": 123 } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_direction_but_non_string_value) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@value": 123, "@direction": "ltr" } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(value_object_with_non_string_index) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@value": "x", "@index": 123 } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(node_with_non_string_index) { + const auto document = + sourcemeta::core::parse_json(R"([ { "@index": 123 } ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(node_type_array_with_invalid_reference) { + const auto document = sourcemeta::core::parse_json(R"([ + { "@type": [ "bad ref with spaces" ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(node_with_non_array_graph) { + const auto document = + sourcemeta::core::parse_json(R"([ { "@graph": "x" } ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(node_with_non_object_reverse) { + const auto document = + sourcemeta::core::parse_json(R"([ { "@reverse": "x" } ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(node_reverse_with_non_iri_key) { + const auto document = sourcemeta::core::parse_json(R"([ + { "@reverse": { "notaterm": [] } } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(list_object_with_non_array_list) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@list": "x" } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} + +TEST(list_object_with_non_string_index) { + const auto document = sourcemeta::core::parse_json(R"([ + { "http://example.com/p": [ { "@list": [], "@index": 123 } ] } + ])"); + EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); +} diff --git a/test/jsonpath/jsonpath_filter_test.cc b/test/jsonpath/jsonpath_filter_test.cc index 8ab9f7c0a4..a7f849ecac 100644 --- a/test/jsonpath/jsonpath_filter_test.cc +++ b/test/jsonpath/jsonpath_filter_test.cc @@ -580,3 +580,39 @@ TEST(jsonpath_filter_negated_search) { EXPECT_EQ(nodes.size(), 1); EXPECT_EQ(nodes.at(0).value->at("a").to_string(), "xyz"); } + +TEST(jsonpath_filter_singular_index_comparison) { + const auto document{ + sourcemeta::core::parse_json(R"JSON([ [ 1, 9 ], [ 5, 9 ] ])JSON")}; + const sourcemeta::core::JSONPath path{"$[?@[0]==1]"}; + const auto nodes{evaluate_nodes(path, document)}; + EXPECT_EQ(nodes.size(), 1); + EXPECT_EQ(nodes.at(0).value->at(0).to_integer(), 1); +} + +TEST(jsonpath_filter_singular_negative_index_comparison) { + const auto document{ + sourcemeta::core::parse_json(R"JSON([ [ 1, 9 ], [ 5, 3 ] ])JSON")}; + const sourcemeta::core::JSONPath path{"$[?@[-1]==9]"}; + const auto nodes{evaluate_nodes(path, document)}; + EXPECT_EQ(nodes.size(), 1); + EXPECT_EQ(nodes.at(0).value->at(1).to_integer(), 9); +} + +TEST(jsonpath_filter_match_over_non_string_subject) { + const auto document{ + sourcemeta::core::parse_json(R"JSON([ { "a": 5 }, { "a": "ab" } ])JSON")}; + const sourcemeta::core::JSONPath path{R"($[?match(@.a, "ab")])"}; + const auto nodes{evaluate_nodes(path, document)}; + EXPECT_EQ(nodes.size(), 1); + EXPECT_EQ(nodes.at(0).value->at("a").to_string(), "ab"); +} + +TEST(jsonpath_filter_search_over_non_string_subject) { + const auto document{sourcemeta::core::parse_json( + R"JSON([ { "a": 5 }, { "a": "xby" } ])JSON")}; + const sourcemeta::core::JSONPath path{R"($[?search(@.a, "b")])"}; + const auto nodes{evaluate_nodes(path, document)}; + EXPECT_EQ(nodes.size(), 1); + EXPECT_EQ(nodes.at(0).value->at("a").to_string(), "xby"); +} diff --git a/test/jsonpath/jsonpath_parse_test.cc b/test/jsonpath/jsonpath_parse_test.cc index 6dbe36adeb..3455bfce94 100644 --- a/test/jsonpath/jsonpath_parse_test.cc +++ b/test/jsonpath/jsonpath_parse_test.cc @@ -437,6 +437,24 @@ TEST(jsonpath_parse_error_value_function_call_as_test){ TEST(jsonpath_parse_error_negated_value_function_as_test){ EXPECT_JSONPATH_PARSE_ERROR("$[?!length(@.a)]", 16)} -TEST(jsonpath_parse_error_negated_literal) { - EXPECT_JSONPATH_PARSE_ERROR("$[?!1]", 5) +TEST(jsonpath_parse_error_negated_literal){ + EXPECT_JSONPATH_PARSE_ERROR("$[?!1]", 5)} + +TEST(jsonpath_parse_error_lone_high_surrogate_at_string_end){ + EXPECT_JSONPATH_PARSE_ERROR("$[\"\\uD800\"]", 10)} + +TEST(jsonpath_parse_error_high_surrogate_then_non_low){ + EXPECT_JSONPATH_PARSE_ERROR("$[\"\\uD800\\u0041\"]", 16)} + +TEST(jsonpath_parse_error_fraction_without_digit){ + EXPECT_JSONPATH_PARSE_ERROR("$[?@.a==1.]", 11)} + +TEST(jsonpath_parse_error_exponent_without_digit){ + EXPECT_JSONPATH_PARSE_ERROR("$[?@.a==1e]", 11)} + +TEST(jsonpath_parse_error_integer_above_maximum){ + EXPECT_JSONPATH_PARSE_ERROR("$[?@.a==999999999999999999]", 27)} + +TEST(jsonpath_parse_error_slice_step_non_digit) { + EXPECT_JSONPATH_PARSE_ERROR("$[1:2:x]", 7) } diff --git a/test/jsonpointer/jsonpointer_pointer_test.cc b/test/jsonpointer/jsonpointer_pointer_test.cc index 04dece8fbf..d37a40acef 100644 --- a/test/jsonpointer/jsonpointer_pointer_test.cc +++ b/test/jsonpointer/jsonpointer_pointer_test.cc @@ -347,3 +347,29 @@ TEST(to_pointer_from_json_string) { const auto pointer{sourcemeta::core::to_pointer(document)}; EXPECT_EQ(pointer, sourcemeta::core::to_pointer("/foo/0")); } + +TEST(push_back_empty_pointer_is_noop) { + sourcemeta::core::Pointer target{"foo"}; + const sourcemeta::core::Pointer other; + target.push_back(other); + EXPECT_EQ(target, sourcemeta::core::Pointer{"foo"}); +} + +TEST(push_back_single_token_pointer) { + sourcemeta::core::Pointer target{"foo"}; + const sourcemeta::core::Pointer other{"bar"}; + target.push_back(other); + EXPECT_EQ(target, (sourcemeta::core::Pointer{"foo", "bar"})); +} + +TEST(push_back_empty_rvalue_pointer_is_noop) { + sourcemeta::core::Pointer target{"foo"}; + target.push_back(sourcemeta::core::Pointer{}); + EXPECT_EQ(target, sourcemeta::core::Pointer{"foo"}); +} + +TEST(push_back_single_token_rvalue_pointer) { + sourcemeta::core::Pointer target{"foo"}; + target.push_back(sourcemeta::core::Pointer{"bar"}); + EXPECT_EQ(target, (sourcemeta::core::Pointer{"foo", "bar"})); +} diff --git a/test/oauth/oauth_dpop_test.cc b/test/oauth/oauth_dpop_test.cc index 91a2aad721..25e4a9ae8d 100644 --- a/test/oauth/oauth_dpop_test.cc +++ b/test/oauth/oauth_dpop_test.cc @@ -1134,3 +1134,13 @@ TEST(replay_store_saturates_a_window_beyond_the_clock) { EXPECT_FALSE(store.check_and_insert("id", "https://server.example.com/token", FIXED_TIME, window)); } + +TEST(proof_thumbprint_rejects_non_object_jwk_header) { + const std::string proof{ + "eyJ0eXAiOiJkcG9wK2p3dCIsImFsZyI6IkVTMjU2IiwiandrIjoibm90LWFuLW9iamVjdCJ9" + ".eyJodHUiOiJodHRwczovL3JzLmV4YW1wbGUuY29tL3giLCJodG0iOiJQT1NUIiwianRpIjo" + "i" + "YWJjIiwiaWF0IjoxNzAwMDAwMDAwfQ.c2ln"}; + EXPECT_FALSE( + sourcemeta::core::oauth_dpop_proof_thumbprint(proof).has_value()); +} diff --git a/test/oauth/oauth_metadata_test.cc b/test/oauth/oauth_metadata_test.cc index 6946302422..03e3bd5a36 100644 --- a/test/oauth/oauth_metadata_test.cc +++ b/test/oauth/oauth_metadata_test.cc @@ -2661,3 +2661,45 @@ TEST(server_metadata_accepts_a_protected_resource_entry_with_a_query) { EXPECT_FALSE(metadata.value().supports_protected_resource( "https://nonexistent.example.invalid")); } + +TEST(server_metadata_rejects_non_string_issuer) { + EXPECT_FALSE(sourcemeta::core::OAuthServerMetadata::from( + sourcemeta::core::parse_json(R"JSON({ "issuer": 123 })JSON"), + "https://as.example.com") + .has_value()); +} + +TEST(server_metadata_rejects_non_array_response_types) { + EXPECT_FALSE(sourcemeta::core::OAuthServerMetadata::from( + sourcemeta::core::parse_json(R"JSON({ + "issuer": "https://as.example.com", + "response_types_supported": 123 + })JSON"), + "https://as.example.com") + .has_value()); +} + +TEST(server_metadata_explicit_false_pushed_authorization) { + const auto metadata{sourcemeta::core::OAuthServerMetadata::from( + sourcemeta::core::parse_json(R"JSON({ + "issuer": "https://as.example.com", + "response_types_supported": [ "code" ], + "require_pushed_authorization_requests": false + })JSON"), + "https://as.example.com")}; + EXPECT_TRUE(metadata.has_value()); + EXPECT_FALSE(metadata.value().require_pushed_authorization_requests()); +} + +TEST(server_metadata_explicit_false_iss_parameter) { + const auto metadata{sourcemeta::core::OAuthServerMetadata::from( + sourcemeta::core::parse_json(R"JSON({ + "issuer": "https://as.example.com", + "response_types_supported": [ "code" ], + "authorization_response_iss_parameter_supported": false + })JSON"), + "https://as.example.com")}; + EXPECT_TRUE(metadata.has_value()); + EXPECT_FALSE( + metadata.value().authorization_response_iss_parameter_supported()); +} diff --git a/test/oauth/oauth_resource_metadata_test.cc b/test/oauth/oauth_resource_metadata_test.cc index e93c4fdff2..3aef778bc9 100644 --- a/test/oauth/oauth_resource_metadata_test.cc +++ b/test/oauth/oauth_resource_metadata_test.cc @@ -2327,3 +2327,25 @@ TEST(make_resource_metadata_accepts_a_cleartext_tos_uri) { })JSON")}; EXPECT_EQ(document.value(), expected); } + +TEST(resource_metadata_explicit_false_dpop_bound) { + const auto metadata{sourcemeta::core::OAuthResourceMetadata::from( + sourcemeta::core::parse_json(R"JSON({ + "resource": "https://rs.example.com", + "dpop_bound_access_tokens_required": false + })JSON"), + "https://rs.example.com")}; + EXPECT_TRUE(metadata.has_value()); + EXPECT_FALSE(metadata.value().dpop_bound_access_tokens_required()); +} + +TEST(resource_metadata_explicit_false_tls_client_cert) { + const auto metadata{sourcemeta::core::OAuthResourceMetadata::from( + sourcemeta::core::parse_json(R"JSON({ + "resource": "https://rs.example.com", + "tls_client_certificate_bound_access_tokens": false + })JSON"), + "https://rs.example.com")}; + EXPECT_TRUE(metadata.has_value()); + EXPECT_FALSE(metadata.value().tls_client_certificate_bound_access_tokens()); +} diff --git a/test/oidc/oidc_authentication_test.cc b/test/oidc/oidc_authentication_test.cc index 8e8d7e0a94..47b046f6fa 100644 --- a/test/oidc/oidc_authentication_test.cc +++ b/test/oidc/oidc_authentication_test.cc @@ -610,3 +610,42 @@ TEST(parse_rejects_a_duplicated_parameter) { EXPECT_FALSE(sourcemeta::core::oidc_parse_authentication_request( "client_id=a&client_id=b&scope=openid", storage, request)); } + +TEST(parse_populates_all_optional_openid_parameters) { + std::string storage; + sourcemeta::core::OIDCAuthenticationRequest request; + EXPECT_TRUE(sourcemeta::core::oidc_parse_authentication_request( + "client_id=x&redirect_uri=https%3A%2F%2Fcb.example.com&scope=openid&" + "response_type=code&display=page&ui_locales=en-US&id_token_hint=abc&" + "login_hint=user&claims=%7B%7D&request=jwt&response_mode=query", + storage, request, sourcemeta::core::OIDCProfile::Legacy)); + EXPECT_EQ(request.display, "page"); + EXPECT_EQ(request.ui_locales, "en-US"); + EXPECT_EQ(request.id_token_hint, "abc"); + EXPECT_EQ(request.login_hint, "user"); + EXPECT_EQ(request.claims, "{}"); + EXPECT_EQ(request.request, "jwt"); + EXPECT_EQ(request.response_mode, "query"); +} + +TEST(parse_accepts_code_challenge_with_underscore) { + std::string storage; + sourcemeta::core::OIDCAuthenticationRequest request; + EXPECT_TRUE(sourcemeta::core::oidc_parse_authentication_request( + "client_id=x&redirect_uri=https%3A%2F%2Fcb.example.com&scope=openid&" + "response_type=code&code_challenge_method=S256&" + "code_challenge=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP_", + storage, request, sourcemeta::core::OIDCProfile::Strict)); + EXPECT_EQ(request.code_challenge, + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP_"); +} + +TEST(parse_drops_offline_access_scope_with_prompt_none) { + std::string storage; + sourcemeta::core::OIDCAuthenticationRequest request; + EXPECT_TRUE(sourcemeta::core::oidc_parse_authentication_request( + "client_id=x&redirect_uri=https%3A%2F%2Fcb.example.com&" + "scope=openid%20offline_access&response_type=code&prompt=none", + storage, request, sourcemeta::core::OIDCProfile::Legacy)); + EXPECT_EQ(request.scope, "openid"); +} diff --git a/test/oidc/oidc_discovery_test.cc b/test/oidc/oidc_discovery_test.cc index 68a342aa60..45e8ab2c0d 100644 --- a/test/oidc/oidc_discovery_test.cc +++ b/test/oidc/oidc_discovery_test.cc @@ -272,3 +272,74 @@ TEST(webfinger_issuer_skips_an_invalid_matching_link) { EXPECT_TRUE(issuer.has_value()); EXPECT_EQ(issuer.value(), "https://example.com"); } + +TEST(webfinger_request_rejects_empty_scheme_candidate) { + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_request(":8080").has_value()); +} + +TEST(webfinger_request_rejects_scheme_first_char_non_alpha) { + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_request("1:foo").has_value()); +} + +TEST(webfinger_request_rejects_invalid_scheme_character) { + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_request("a b:x").has_value()); +} + +TEST(webfinger_request_rejects_acct_without_at) { + EXPECT_FALSE( + sourcemeta::core::oidc_webfinger_request("acct:foo").has_value()); +} + +TEST(webfinger_request_rejects_acct_with_empty_host) { + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_request("foo@").has_value()); +} + +TEST(webfinger_issuer_rejects_non_object) { + EXPECT_FALSE( + sourcemeta::core::oidc_webfinger_issuer(sourcemeta::core::JSON{"string"}) + .has_value()); +} + +TEST(webfinger_issuer_rejects_non_array_links) { + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer( + sourcemeta::core::parse_json(R"({ "links": "x" })")) + .has_value()); +} + +TEST(webfinger_issuer_rejects_non_object_link) { + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer( + sourcemeta::core::parse_json(R"({ "links": [ 123 ] })")) + .has_value()); +} + +TEST(webfinger_issuer_skips_link_without_rel) { + EXPECT_FALSE( + sourcemeta::core::oidc_webfinger_issuer( + sourcemeta::core::parse_json( + R"({ "links": [ { "href": "https://issuer.example.com" } ] })")) + .has_value()); +} + +TEST(webfinger_issuer_skips_link_with_non_string_rel) { + EXPECT_FALSE( + sourcemeta::core::oidc_webfinger_issuer( + sourcemeta::core::parse_json( + R"({ "links": [ { "rel": 123, "href": "https://issuer.example.com" } ] })")) + .has_value()); +} + +TEST(webfinger_issuer_skips_link_with_other_rel) { + EXPECT_FALSE( + sourcemeta::core::oidc_webfinger_issuer( + sourcemeta::core::parse_json( + R"({ "links": [ { "rel": "other", "href": "https://issuer.example.com" } ] })")) + .has_value()); +} + +TEST(webfinger_issuer_rejects_matching_rel_with_non_string_href) { + EXPECT_FALSE( + sourcemeta::core::oidc_webfinger_issuer( + sourcemeta::core::parse_json( + R"({ "links": [ { "rel": "http://openid.net/specs/connect/1.0/issuer", "href": 123 } ] })")) + .has_value()); +} diff --git a/test/oidc/oidc_registration_test.cc b/test/oidc/oidc_registration_test.cc index d2c973c839..9adc090515 100644 --- a/test/oidc/oidc_registration_test.cc +++ b/test/oidc/oidc_registration_test.cc @@ -448,3 +448,79 @@ TEST(encrypted_and_userinfo_algorithm_accessors) { EXPECT_TRUE(metadata.value().userinfo_signed_response_alg().has_value()); EXPECT_EQ(metadata.value().userinfo_signed_response_alg().value(), "ES256"); } + +TEST(from_rejects_non_array_redirect_uris) { + EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from( + sourcemeta::core::parse_json(R"({ "redirect_uris": "x" })")) + .has_value()); +} + +TEST(from_rejects_non_string_redirect_uri_element) { + EXPECT_FALSE( + sourcemeta::core::OIDCClientMetadata::from( + sourcemeta::core::parse_json(R"({ "redirect_uris": [ 123 ] })")) + .has_value()); +} + +TEST(from_rejects_non_string_subject_type) { + EXPECT_FALSE( + sourcemeta::core::OIDCClientMetadata::from( + sourcemeta::core::parse_json( + R"({ "redirect_uris": [ "https://cb.example.com" ], "subject_type": 123 })")) + .has_value()); +} + +TEST(from_rejects_non_string_id_token_signed_alg) { + EXPECT_FALSE( + sourcemeta::core::OIDCClientMetadata::from( + sourcemeta::core::parse_json( + R"({ "redirect_uris": [ "https://cb.example.com" ], "id_token_signed_response_alg": 123 })")) + .has_value()); +} + +TEST(from_rejects_non_string_id_token_encrypted_alg) { + EXPECT_FALSE( + sourcemeta::core::OIDCClientMetadata::from( + sourcemeta::core::parse_json( + R"({ "redirect_uris": [ "https://cb.example.com" ], "id_token_encrypted_response_alg": 123 })")) + .has_value()); +} + +TEST(from_rejects_non_string_userinfo_signed_alg) { + EXPECT_FALSE( + sourcemeta::core::OIDCClientMetadata::from( + sourcemeta::core::parse_json( + R"({ "redirect_uris": [ "https://cb.example.com" ], "userinfo_signed_response_alg": 123 })")) + .has_value()); +} + +TEST(from_rejects_non_string_sector_identifier_uri) { + EXPECT_FALSE( + sourcemeta::core::OIDCClientMetadata::from( + sourcemeta::core::parse_json( + R"({ "redirect_uris": [ "https://cb.example.com" ], "sector_identifier_uri": 123 })")) + .has_value()); +} + +TEST(from_rejects_non_string_initiate_login_uri) { + EXPECT_FALSE( + sourcemeta::core::OIDCClientMetadata::from( + sourcemeta::core::parse_json( + R"({ "redirect_uris": [ "https://cb.example.com" ], "initiate_login_uri": 123 })")) + .has_value()); +} + +TEST(from_accepts_valid_initiate_login_uri) { + const auto metadata{ + sourcemeta::core::OIDCClientMetadata::from(sourcemeta::core::parse_json( + R"({ "redirect_uris": [ "https://cb.example.com" ], "initiate_login_uri": "https://login.example.com" })"))}; + EXPECT_TRUE(metadata.has_value()); +} + +TEST(require_auth_time_false_accessor) { + const auto metadata{ + sourcemeta::core::OIDCClientMetadata::from(sourcemeta::core::parse_json( + R"({ "redirect_uris": [ "https://cb.example.com" ], "require_auth_time": false })"))}; + EXPECT_TRUE(metadata.has_value()); + EXPECT_FALSE(metadata.value().require_auth_time()); +} diff --git a/test/regex/regex_rfc9485_matches_test.cc b/test/regex/regex_rfc9485_matches_test.cc index 5565dd4de5..20c30643d8 100644 --- a/test/regex/regex_rfc9485_matches_test.cc +++ b/test/regex/regex_rfc9485_matches_test.cc @@ -1127,3 +1127,76 @@ TEST(rfc9485_matches_class_double_dash) { EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "-")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } + +TEST(iregexp_mark_category) { + EXPECT_TRUE(sourcemeta::core::to_regex( + "\\p{M}", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_punctuation_category) { + EXPECT_TRUE(sourcemeta::core::to_regex( + "\\p{P}", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_separator_category) { + EXPECT_TRUE(sourcemeta::core::to_regex( + "\\p{Z}", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_symbol_category) { + EXPECT_TRUE(sourcemeta::core::to_regex( + "\\p{S}", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_number_category_single_letter) { + EXPECT_TRUE(sourcemeta::core::to_regex( + "\\p{N}", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_other_category_single_letter) { + EXPECT_TRUE(sourcemeta::core::to_regex( + "\\p{C}", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_letter_subcategory_invalid) { + EXPECT_FALSE(sourcemeta::core::to_regex( + "\\p{Lx}", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_property_at_end_incomplete) { + EXPECT_FALSE( + sourcemeta::core::to_regex("\\p", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_malformed_utf8_pattern) { + EXPECT_FALSE( + sourcemeta::core::to_regex(std::string_view{"\xC3\x28", 2}, + sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_unclosed_nested_class) { + EXPECT_FALSE( + sourcemeta::core::to_regex("[a[", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_quantifier_max_overflow) { + EXPECT_FALSE(sourcemeta::core::to_regex( + "a{0,9999999999}", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} + +TEST(iregexp_quantifier_junk_after_digits) { + EXPECT_FALSE(sourcemeta::core::to_regex( + "a{1x}", sourcemeta::core::RegexDialect::IRegexp) + .has_value()); +} diff --git a/test/regex/regex_to_regex_test.cc b/test/regex/regex_to_regex_test.cc index 593a69732e..7f909238b6 100644 --- a/test/regex/regex_to_regex_test.cc +++ b/test/regex/regex_to_regex_test.cc @@ -91,3 +91,15 @@ TEST(oversized_unicode_brace_escape_does_not_overflow) { const auto regex{sourcemeta::core::to_regex("\\u{FFFFFFFFFFFFFFFFFFFFFFFF}")}; EXPECT_FALSE(regex.has_value()); } + +TEST(permissive_named_group_uppercase_start) { + EXPECT_TRUE(sourcemeta::core::to_regex("(?x)").has_value()); +} + +TEST(permissive_named_group_underscore_start) { + EXPECT_TRUE(sourcemeta::core::to_regex("(?<_a>x)").has_value()); +} + +TEST(permissive_negated_unicode_property) { + EXPECT_TRUE(sourcemeta::core::to_regex("\\P{Letter}").has_value()); +} diff --git a/test/time/imf_fixdate_test.cc b/test/time/imf_fixdate_test.cc index 78786fcb5e..06d368d080 100644 --- a/test/time/imf_fixdate_test.cc +++ b/test/time/imf_fixdate_test.cc @@ -297,3 +297,123 @@ TEST(format_year_below_1000_pads_to_four_digits) { EXPECT_EQ(sourcemeta::core::from_imf_fixdate(formatted), point); } } + +TEST(rejects_separator_at_3) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun. 06 Nov 1994 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_separator_at_4) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun,_06 Nov 1994 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_separator_at_7) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06_Nov 1994 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_separator_at_11) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov_1994 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_separator_at_16) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994_08:49:37 GMT") + .has_value()); +} + +TEST(rejects_separator_at_19) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994 08.49:37 GMT") + .has_value()); +} + +TEST(rejects_separator_at_22) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994 08:49.37 GMT") + .has_value()); +} + +TEST(rejects_separator_at_25) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994 08:49:37_GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_5) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, X6 Nov 1994 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_6) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 0X Nov 1994 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_12) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov X994 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_13) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1X94 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_14) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 19X4 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_15) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 199X 08:49:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_17) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994 X8:49:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_18) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994 0X:49:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_20) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994 08:X9:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_21) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994 08:4X:37 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_23) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994 08:49:X7 GMT") + .has_value()); +} + +TEST(rejects_non_digit_at_24) { + EXPECT_FALSE( + sourcemeta::core::from_imf_fixdate("Sun, 06 Nov 1994 08:49:3X GMT") + .has_value()); +} diff --git a/test/uri/uri_parse_test.cc b/test/uri/uri_parse_test.cc index 8de6b29342..eee98b2f96 100644 --- a/test/uri/uri_parse_test.cc +++ b/test/uri/uri_parse_test.cc @@ -947,3 +947,25 @@ TEST(uri_constructor_rejects_non_ascii) { EXPECT_EQ(error.column(), 24); } } + +TEST(ipvfuture_uppercase_marker) { + const sourcemeta::core::URI uri{"http://[V1.a]/"}; + EXPECT_TRUE(uri.host().has_value()); + EXPECT_EQ(uri.host().value(), "V1.a"); +} + +TEST(ipvfuture_missing_version_hexdigit) { + EXPECT_FALSE(sourcemeta::core::URI::is_uri("http://[v.a]/")); +} + +TEST(ipvfuture_missing_dot_separator) { + EXPECT_FALSE(sourcemeta::core::URI::is_uri("http://[v1x]/")); +} + +TEST(ipvfuture_missing_content_after_dot) { + EXPECT_FALSE(sourcemeta::core::URI::is_uri("http://[v1.]/")); +} + +TEST(ipvfuture_invalid_content_character) { + EXPECT_FALSE(sourcemeta::core::URI::is_uri("http://[v1.a%]/")); +} diff --git a/test/uri/uri_path_test.cc b/test/uri/uri_path_test.cc index 7e84bcac1f..1e15d03bf5 100644 --- a/test/uri/uri_path_test.cc +++ b/test/uri/uri_path_test.cc @@ -990,3 +990,73 @@ TEST(append_path_that_normalizes_away) { uri.append_path(".."); EXPECT_EQ(uri.recompose(), ""); } + +TEST(set_path_second_percent_digit_invalid) { + sourcemeta::core::URI uri{"http://example.com"}; + try { + uri.path("/%Ag"); + FAIL(); + } catch (const sourcemeta::core::URIError &) { + } +} + +TEST(set_path_with_sub_delim) { + sourcemeta::core::URI uri{"http://example.com"}; + uri.path("/a!b"); + EXPECT_EQ(uri.path().value(), "/a!b"); +} + +TEST(set_path_with_colon) { + sourcemeta::core::URI uri{"http://example.com"}; + uri.path("/a:b"); + EXPECT_EQ(uri.path().value(), "/a:b"); +} + +TEST(set_path_with_at_sign) { + sourcemeta::core::URI uri{"http://example.com"}; + uri.path("/a@b"); + EXPECT_EQ(uri.path().value(), "/a@b"); +} + +TEST(set_rvalue_path_with_host_no_scheme) { + sourcemeta::core::URI uri{"//example.com"}; + uri.path(std::string{"foo"}); + EXPECT_EQ(uri.recompose(), "//example.com/foo"); +} + +TEST(set_const_path_with_host_no_scheme) { + sourcemeta::core::URI uri{"//example.com"}; + const std::string value{"foo"}; + uri.path(value); + EXPECT_EQ(uri.recompose(), "//example.com/foo"); +} + +TEST(append_path_view_with_host_no_scheme) { + sourcemeta::core::URI uri{"//example.com"}; + uri.append_path("foo"); + EXPECT_EQ(uri.recompose(), "//example.com/foo"); +} + +TEST(append_path_reference_with_host_no_scheme) { + sourcemeta::core::URI uri{"//example.com"}; + uri.append_path(sourcemeta::core::URI{"rel"}); + EXPECT_EQ(uri.recompose(), "//example.com/rel"); +} + +TEST(append_path_rejects_reference_with_userinfo) { + sourcemeta::core::URI uri{"http://x"}; + try { + uri.append_path(sourcemeta::core::URI{"//user@host"}); + FAIL(); + } catch (const sourcemeta::core::URIError &) { + } +} + +TEST(append_path_rejects_reference_with_fragment) { + sourcemeta::core::URI uri{"http://x"}; + try { + uri.append_path(sourcemeta::core::URI{"#frag"}); + FAIL(); + } catch (const sourcemeta::core::URIError &) { + } +} diff --git a/test/uri/uri_relative_to_test.cc b/test/uri/uri_relative_to_test.cc index 49b8119e63..580a467434 100644 --- a/test/uri/uri_relative_to_test.cc +++ b/test/uri/uri_relative_to_test.cc @@ -370,3 +370,28 @@ TEST(authority_no_path_base_query_target_none) { uri.relative_to(base); EXPECT_EQ(uri.recompose(), "https://www.example.com"); } + +TEST(relative_to_same_path_with_query_in_base) { + sourcemeta::core::URI target{"schema:foo?bar=1"}; + target.relative_to(sourcemeta::core::URI{"schema:foo"}); + EXPECT_EQ(target.recompose(), "?bar=1"); +} + +TEST(relative_to_sibling_directory_yields_empty) { + sourcemeta::core::URI target{"https://example.com/test/"}; + target.relative_to( + sourcemeta::core::URI{"https://example.com/test/foo.json"}); + EXPECT_EQ(target.recompose(), ""); +} + +TEST(relative_to_root_from_authority_yields_empty) { + sourcemeta::core::URI target{"https://example.com/"}; + target.relative_to(sourcemeta::core::URI{"https://example.com"}); + EXPECT_EQ(target.recompose(), ""); +} + +TEST(relative_to_slashless_base_path) { + sourcemeta::core::URI target{"schema:bar"}; + target.relative_to(sourcemeta::core::URI{"schema:foo"}); + EXPECT_EQ(target.recompose(), "schema:bar"); +} diff --git a/test/uritemplate/uritemplate_parse_error_test.cc b/test/uritemplate/uritemplate_parse_error_test.cc index caf4fb288f..5659175a12 100644 --- a/test/uritemplate/uritemplate_parse_error_test.cc +++ b/test/uritemplate/uritemplate_parse_error_test.cc @@ -199,3 +199,7 @@ TEST(modifier_without_varname) { EXPECT_URITEMPLATE_PARSE_ERROR("{:1}", 2); } TEST(two_prefix_modifiers) { EXPECT_URITEMPLATE_PARSE_ERROR("{a:1:2}", 5); } TEST(varname_after_explode) { EXPECT_URITEMPLATE_PARSE_ERROR("{a*b}", 4); } + +TEST(prefix_colon_not_followed_by_positive_digit) { + EXPECT_URITEMPLATE_PARSE_ERROR("{a:x}", 4); +} diff --git a/test/yaml/yaml_parse_test.cc b/test/yaml/yaml_parse_test.cc index 02070461b4..c4bde15f1b 100644 --- a/test/yaml/yaml_parse_test.cc +++ b/test/yaml/yaml_parse_test.cc @@ -3,8 +3,9 @@ #include #include -#include // std::istringstream -#include // std::string +#include // std::cerr +#include // std::istringstream +#include // std::string TEST(deeply_nested_flow_is_rejected) { const std::string input{std::string(2000, '[') + std::string(2000, ']')}; @@ -1739,3 +1740,275 @@ TEST(alias_quoted_keyword_key_is_preserved) { R"JSON([ "null", { "null": "value" } ])JSON")}; EXPECT_EQ(result, expected); } + +TEST(escape_vertical_tab) { + const std::string input{"\"\\v\""}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), std::string("\x0b", 1)); +} + +TEST(escape_form_feed) { + const std::string input{"\"\\f\""}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), std::string("\x0c", 1)); +} + +TEST(escape_line_separator) { + const std::string input{"\"\\L\""}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), std::string("\xe2\x80\xa8", 3)); +} + +TEST(escape_paragraph_separator) { + const std::string input{"\"\\P\""}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), std::string("\xe2\x80\xa9", 3)); +} + +TEST(escape_incomplete_hex) { + const std::string input{"\"\\xZ\""}; + try { + const auto result{sourcemeta::core::parse_yaml(input)}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(unterminated_single_quote) { + const std::string input{"'abc"}; + try { + const auto result{sourcemeta::core::parse_yaml(input)}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(single_quoted_cr_folds_to_space) { + const std::string input{"'a\rb'"}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_EQ(result.to_string(), "a b"); +} + +TEST(single_quoted_crlf_folds_to_space) { + const std::string input{"'a\r\nb'"}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_EQ(result.to_string(), "a b"); +} + +TEST(double_quoted_cr_folds_to_space) { + const std::string input{"\"a\rb\""}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_EQ(result.to_string(), "a b"); +} + +TEST(double_quoted_escaped_cr_line_continuation) { + const std::string input{"\"a\\\rb\""}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_EQ(result.to_string(), "ab"); +} + +TEST(double_quoted_escaped_crlf_line_continuation) { + const std::string input{"\"a\\\r\nb\""}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_EQ(result.to_string(), "ab"); +} + +TEST(block_scalar_with_cr_line_breaks) { + const std::string input{"|\r a\r b\r"}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_EQ(result.to_string(), "a\nb\n"); +} + +TEST(block_scalar_with_crlf_line_breaks) { + const std::string input{"|\r\n a\r\n b\r\n"}; + const auto result{sourcemeta::core::parse_yaml(input)}; + EXPECT_EQ(result.to_string(), "a\nb\n"); +} + +TEST(flow_mapping_bare_key_at_eof_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("{a")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(flow_mapping_colon_at_eof_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("{a:")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(flow_mapping_anchor_key_at_eof_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("{&a")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(explicit_bool_true_capitalized) { + const auto result{sourcemeta::core::parse_yaml("!!bool True")}; + EXPECT_TRUE(result.is_boolean()); + EXPECT_TRUE(result.to_boolean()); +} + +TEST(explicit_bool_true_uppercase) { + const auto result{sourcemeta::core::parse_yaml("!!bool TRUE")}; + EXPECT_TRUE(result.is_boolean()); + EXPECT_TRUE(result.to_boolean()); +} + +TEST(sign_only_scalar_is_a_string) { + const auto result{sourcemeta::core::parse_yaml("+")}; + EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), "+"); +} + +TEST(dot_after_exponent_is_a_string) { + const auto result{sourcemeta::core::parse_yaml("1e1.5")}; + EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), "1e1.5"); +} + +TEST(double_exponent_is_a_string) { + const auto result{sourcemeta::core::parse_yaml("1e2e3")}; + EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), "1e2e3"); +} + +TEST(line_starting_with_double_dash_non_marker) { + const auto result{sourcemeta::core::parse_yaml("--x")}; + EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), "--x"); +} + +TEST(flow_mapping_colon_before_flow_indicator) { + const auto result{sourcemeta::core::parse_yaml("{a:}")}; + EXPECT_TRUE(result.is_object()); + EXPECT_TRUE(result.defines("a")); +} + +TEST(colon_as_final_byte_no_newline) { + const auto result{sourcemeta::core::parse_yaml("a:")}; + EXPECT_TRUE(result.is_object()); + EXPECT_TRUE(result.defines("a")); +} + +TEST(flow_sequence_dash_at_eof_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("[-")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(anchor_with_empty_value_before_document_end) { + const auto result{sourcemeta::core::parse_yaml("&a\n...")}; + EXPECT_TRUE(result.is_null()); +} + +TEST(tag_then_flow_mapping_end) { + const auto result{sourcemeta::core::parse_yaml("{ a: !!str }")}; + EXPECT_TRUE(result.is_object()); + EXPECT_TRUE(result.defines("a")); +} + +TEST(tag_then_flow_sequence_end) { + const auto result{sourcemeta::core::parse_yaml("[ !!str ]")}; + EXPECT_TRUE(result.is_array()); + EXPECT_EQ(result.size(), 1); +} + +TEST(alias_key_referencing_unknown_anchor_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("*a: b")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(flow_explicit_key_at_eof_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("[?")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(flow_collection_indented_at_parent_block_level_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("a: [\n1]")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(explicit_key_block_mapping_duplicate_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("? a\n: 1\n? a\n: 2")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(explicit_key_value_at_document_end) { + const auto result{sourcemeta::core::parse_yaml("? a\n:\n...")}; + EXPECT_TRUE(result.is_object()); + EXPECT_TRUE(result.defines("a")); +} + +TEST(block_mapping_second_key_value_at_document_end) { + const auto result{sourcemeta::core::parse_yaml("a: 1\nb:\n...")}; + EXPECT_TRUE(result.is_object()); + EXPECT_EQ(result.at("a").to_integer(), 1); + EXPECT_TRUE(result.at("b").is_null()); +} + +TEST(leading_colon_value_indicator_mapping) { + const auto result{sourcemeta::core::parse_yaml(": v")}; + EXPECT_TRUE(result.is_object()); +} + +TEST(anchor_empty_value_before_document_start) { + const auto result{sourcemeta::core::parse_yaml("&a\n---\nb")}; + EXPECT_TRUE(result.is_null()); +} + +TEST(mapping_key_that_is_a_collection_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("[? {a: 1}: b]")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(tab_trailing_after_quoted_scalar_is_rejected) { + try { + const auto result{sourcemeta::core::parse_yaml("'x'\tbad")}; + FAIL(); + } catch (const sourcemeta::core::YAMLParseError &) { + } +} + +TEST(cr_trailing_after_quoted_scalar) { + const auto result{sourcemeta::core::parse_yaml("'x'\r")}; + EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), "x"); +} + +TEST(block_scalar_blank_lines_with_cr) { + const auto result{sourcemeta::core::parse_yaml("|\r a\r\r b")}; + EXPECT_TRUE(result.is_string()); +} + +TEST(tab_after_escaped_line_break) { + const auto result{sourcemeta::core::parse_yaml("\"a\\\n\tb\"")}; + EXPECT_TRUE(result.is_string()); +} diff --git a/test/yaml/yaml_stringify_test.cc b/test/yaml/yaml_stringify_test.cc index 964ddd7bb9..df44482f0d 100644 --- a/test/yaml/yaml_stringify_test.cc +++ b/test/yaml/yaml_stringify_test.cc @@ -913,3 +913,66 @@ TEST(string_with_quote_backslash_and_newline) { sourcemeta::core::stringify_yaml(document, stream); EXPECT_EQ(stream.str(), "\"a\\\"b\\\\c\\nd\"\n"); } + +TEST(quotes_uppercase_hex_lookalike) { + const sourcemeta::core::JSON document{"0X1"}; + std::ostringstream stream; + sourcemeta::core::stringify_yaml(document, stream); + EXPECT_EQ(stream.str(), "\"0X1\"\n"); +} + +TEST(quotes_uppercase_exponent_lookalike) { + const sourcemeta::core::JSON document{"1E5"}; + std::ostringstream stream; + sourcemeta::core::stringify_yaml(document, stream); + EXPECT_EQ(stream.str(), "\"1E5\"\n"); +} + +TEST(quotes_positive_exponent_lookalike) { + const sourcemeta::core::JSON document{"1e+5"}; + std::ostringstream stream; + sourcemeta::core::stringify_yaml(document, stream); + EXPECT_EQ(stream.str(), "\"1e+5\"\n"); +} + +TEST(quotes_negative_exponent_lookalike) { + const sourcemeta::core::JSON document{"1e-5"}; + std::ostringstream stream; + sourcemeta::core::stringify_yaml(document, stream); + EXPECT_EQ(stream.str(), "\"1e-5\"\n"); +} + +TEST(quotes_uppercase_positive_infinity) { + const sourcemeta::core::JSON document{".INF"}; + std::ostringstream stream; + sourcemeta::core::stringify_yaml(document, stream); + EXPECT_EQ(stream.str(), "\".INF\"\n"); +} + +TEST(quotes_signed_positive_infinity) { + const sourcemeta::core::JSON document{"+.inf"}; + std::ostringstream stream; + sourcemeta::core::stringify_yaml(document, stream); + EXPECT_EQ(stream.str(), "\"+.inf\"\n"); +} + +TEST(quotes_signed_negative_infinity) { + const sourcemeta::core::JSON document{"-.Inf"}; + std::ostringstream stream; + sourcemeta::core::stringify_yaml(document, stream); + EXPECT_EQ(stream.str(), "\"-.Inf\"\n"); +} + +TEST(quotes_uppercase_nan) { + const sourcemeta::core::JSON document{".NAN"}; + std::ostringstream stream; + sourcemeta::core::stringify_yaml(document, stream); + EXPECT_EQ(stream.str(), "\".NAN\"\n"); +} + +TEST(quotes_document_marker_with_tab) { + const sourcemeta::core::JSON document{"---\t"}; + std::ostringstream stream; + sourcemeta::core::stringify_yaml(document, stream); + EXPECT_EQ(stream.str(), "\"---\\t\"\n"); +} From 68e30a3f32f88d6d376e71cd92d9e7ad953c2ee1 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 7 Aug 2026 17:15:50 -0300 Subject: [PATCH 2/6] Fix Signed-off-by: Juan Cruz Viotti --- test/json/json_value_test.cc | 28 ++++++++++++---------- test/jsonld/jsonld_expand_test.cc | 24 ++++++++++++------- test/uri/uri_path_test.cc | 15 +++++++++--- test/yaml/yaml_parse_test.cc | 39 +++++++++++++++++++++---------- 4 files changed, 71 insertions(+), 35 deletions(-) diff --git a/test/json/json_value_test.cc b/test/json/json_value_test.cc index 0a6bddf252..9d6d6279b8 100644 --- a/test/json/json_value_test.cc +++ b/test/json/json_value_test.cc @@ -1,9 +1,10 @@ #include #include -#include // std::size_t -#include // std::int64_t +#include // std::size_t +#include #include // std::reference_wrapper +#include // std::int64_t #include // std::string #include // std::is_default_constructible, etc #include // std::unordered_map @@ -845,20 +846,24 @@ TEST(deep_copy_of_a_nested_object) { TEST(add_integer_overflow_promotes_to_decimal) { const sourcemeta::core::JSON left{std::numeric_limits::min()}; const sourcemeta::core::JSON right{-1}; - // The integer sum overflows int64, so the operator promotes to Decimal. - // The promoted result is currently rounded to the decimal working precision - // rather than exact (tracked in the decimal precision bug report), so this - // asserts only that the overflow branch is taken + // The integer sum overflows int64, so the operator promotes to Decimal. The + // exact value would be -9223372036854775809, but the Decimal add currently + // rounds to the working precision (tracked in the decimal precision bug + // report). Pin the exact current output so a change in either direction is + // caught const auto result{left + right}; EXPECT_TRUE(result.is_decimal()); + EXPECT_EQ(result.to_decimal().to_string(), "-9.223372036854776e+18"); } TEST(subtract_integer_overflow_promotes_to_decimal) { const sourcemeta::core::JSON left{std::numeric_limits::max()}; const sourcemeta::core::JSON right{-1}; - // See the note on the addition overflow test above + // See the note on the addition overflow test above. Exact value would be + // 9223372036854775808; pin the current rounded output const auto result{left - right}; EXPECT_TRUE(result.is_decimal()); + EXPECT_EQ(result.to_decimal().to_string(), "9.223372036854776e+18"); } TEST(copy_self_assignment) { @@ -887,7 +892,7 @@ TEST(real_below_int64_range_throws_on_as_integer) { try { static_cast(value.as_integer()); FAIL(); - } catch (...) { + } catch (const std::out_of_range &) { } } @@ -898,14 +903,13 @@ TEST(empty_on_string_returns_false) { TEST(fast_hash_of_real_below_int64_range) { const sourcemeta::core::JSON value{-1e300}; - static_cast(value.fast_hash()); - EXPECT_TRUE(value.is_real()); + // A real outside the int64 range falls back to the real type hash + EXPECT_EQ(value.fast_hash(), 5); } TEST(fast_hash_of_real_above_int64_range) { const sourcemeta::core::JSON value{1e300}; - static_cast(value.fast_hash()); - EXPECT_TRUE(value.is_real()); + EXPECT_EQ(value.fast_hash(), 5); } TEST(merge_object_key_over_non_object_source) { diff --git a/test/jsonld/jsonld_expand_test.cc b/test/jsonld/jsonld_expand_test.cc index f2faba6972..d2d7b6d0a5 100644 --- a/test/jsonld/jsonld_expand_test.cc +++ b/test/jsonld/jsonld_expand_test.cc @@ -568,7 +568,8 @@ TEST(type_array_with_non_string_item_is_rejected) { try { const auto result{sourcemeta::core::jsonld_expand(input)}; FAIL(); - } catch (const sourcemeta::core::JSONLDError &) { + } catch (const sourcemeta::core::JSONLDError &error) { + EXPECT_STREQ(error.what(), "Invalid type value"); } } @@ -577,7 +578,8 @@ TEST(top_level_non_string_direction_is_rejected) { try { const auto result{sourcemeta::core::jsonld_expand(input)}; FAIL(); - } catch (const sourcemeta::core::JSONLDError &) { + } catch (const sourcemeta::core::JSONLDError &error) { + EXPECT_STREQ(error.what(), "Invalid base direction"); } } @@ -589,7 +591,8 @@ TEST(nest_array_item_not_an_object_is_rejected) { try { const auto result{sourcemeta::core::jsonld_expand(input)}; FAIL(); - } catch (const sourcemeta::core::JSONLDError &) { + } catch (const sourcemeta::core::JSONLDError &error) { + EXPECT_STREQ(error.what(), "Invalid @nest value"); } } @@ -601,7 +604,8 @@ TEST(nest_array_item_value_object_is_rejected) { try { const auto result{sourcemeta::core::jsonld_expand(input)}; FAIL(); - } catch (const sourcemeta::core::JSONLDError &) { + } catch (const sourcemeta::core::JSONLDError &error) { + EXPECT_STREQ(error.what(), "Invalid @nest value"); } } @@ -613,7 +617,8 @@ TEST(term_container_array_with_non_string_is_rejected) { try { const auto result{sourcemeta::core::jsonld_expand(input)}; FAIL(); - } catch (const sourcemeta::core::JSONLDError &) { + } catch (const sourcemeta::core::JSONLDError &error) { + EXPECT_STREQ(error.what(), "Invalid container mapping"); } } @@ -625,7 +630,8 @@ TEST(term_container_array_with_invalid_container_is_rejected) { try { const auto result{sourcemeta::core::jsonld_expand(input)}; FAIL(); - } catch (const sourcemeta::core::JSONLDError &) { + } catch (const sourcemeta::core::JSONLDError &error) { + EXPECT_STREQ(error.what(), "Invalid container mapping"); } } @@ -637,7 +643,8 @@ TEST(term_direction_non_string_is_rejected) { try { const auto result{sourcemeta::core::jsonld_expand(input)}; FAIL(); - } catch (const sourcemeta::core::JSONLDError &) { + } catch (const sourcemeta::core::JSONLDError &error) { + EXPECT_STREQ(error.what(), "Invalid base direction"); } } @@ -649,6 +656,7 @@ TEST(term_nest_non_string_is_rejected) { try { const auto result{sourcemeta::core::jsonld_expand(input)}; FAIL(); - } catch (const sourcemeta::core::JSONLDError &) { + } catch (const sourcemeta::core::JSONLDError &error) { + EXPECT_STREQ(error.what(), "Invalid @nest value"); } } diff --git a/test/uri/uri_path_test.cc b/test/uri/uri_path_test.cc index 1e15d03bf5..2b7c3b282b 100644 --- a/test/uri/uri_path_test.cc +++ b/test/uri/uri_path_test.cc @@ -996,7 +996,10 @@ TEST(set_path_second_percent_digit_invalid) { try { uri.path("/%Ag"); FAIL(); - } catch (const sourcemeta::core::URIError &) { + } catch (const sourcemeta::core::URIError &error) { + EXPECT_STREQ( + error.what(), + "You cannot set a path with an invalid percent-encoded sequence"); } } @@ -1048,7 +1051,10 @@ TEST(append_path_rejects_reference_with_userinfo) { try { uri.append_path(sourcemeta::core::URI{"//user@host"}); FAIL(); - } catch (const sourcemeta::core::URIError &) { + } catch (const sourcemeta::core::URIError &error) { + EXPECT_STREQ( + error.what(), + "Cannot append a URI as a path that contains a scheme or authority"); } } @@ -1057,6 +1063,9 @@ TEST(append_path_rejects_reference_with_fragment) { try { uri.append_path(sourcemeta::core::URI{"#frag"}); FAIL(); - } catch (const sourcemeta::core::URIError &) { + } catch (const sourcemeta::core::URIError &error) { + EXPECT_STREQ( + error.what(), + "Cannot append a URI as a path that contains a query or fragment"); } } diff --git a/test/yaml/yaml_parse_test.cc b/test/yaml/yaml_parse_test.cc index c4bde15f1b..0e671d2cd0 100644 --- a/test/yaml/yaml_parse_test.cc +++ b/test/yaml/yaml_parse_test.cc @@ -1774,7 +1774,8 @@ TEST(escape_incomplete_hex) { try { const auto result{sourcemeta::core::parse_yaml(input)}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Invalid hex escape sequence"); } } @@ -1783,7 +1784,8 @@ TEST(unterminated_single_quote) { try { const auto result{sourcemeta::core::parse_yaml(input)}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Missing closing quote in single-quoted scalar"); } } @@ -1833,7 +1835,8 @@ TEST(flow_mapping_bare_key_at_eof_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("{a")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Expected ':' after mapping key"); } } @@ -1841,7 +1844,8 @@ TEST(flow_mapping_colon_at_eof_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("{a:")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Unexpected token"); } } @@ -1849,7 +1853,8 @@ TEST(flow_mapping_anchor_key_at_eof_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("{&a")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Expected scalar key in mapping"); } } @@ -1905,7 +1910,8 @@ TEST(flow_sequence_dash_at_eof_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("[-")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Invalid plain scalar start in flow context"); } } @@ -1930,7 +1936,8 @@ TEST(alias_key_referencing_unknown_anchor_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("*a: b")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "YAML alias references undefined anchor"); } } @@ -1938,7 +1945,8 @@ TEST(flow_explicit_key_at_eof_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("[?")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Unexpected token"); } } @@ -1946,7 +1954,8 @@ TEST(flow_collection_indented_at_parent_block_level_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("a: [\n1]")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Insufficient indentation in flow collection"); } } @@ -1954,7 +1963,8 @@ TEST(explicit_key_block_mapping_duplicate_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("? a\n: 1\n? a\n: 2")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Duplicate key in YAML mapping"); } } @@ -1974,6 +1984,7 @@ TEST(block_mapping_second_key_value_at_document_end) { TEST(leading_colon_value_indicator_mapping) { const auto result{sourcemeta::core::parse_yaml(": v")}; EXPECT_TRUE(result.is_object()); + EXPECT_EQ(result.size(), 1); } TEST(anchor_empty_value_before_document_start) { @@ -1985,7 +1996,8 @@ TEST(mapping_key_that_is_a_collection_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("[? {a: 1}: b]")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Mapping key cannot be a collection"); } } @@ -1993,7 +2005,8 @@ TEST(tab_trailing_after_quoted_scalar_is_rejected) { try { const auto result{sourcemeta::core::parse_yaml("'x'\tbad")}; FAIL(); - } catch (const sourcemeta::core::YAMLParseError &) { + } catch (const sourcemeta::core::YAMLParseError &error) { + EXPECT_STREQ(error.what(), "Invalid trailing content"); } } @@ -2006,9 +2019,11 @@ TEST(cr_trailing_after_quoted_scalar) { TEST(block_scalar_blank_lines_with_cr) { const auto result{sourcemeta::core::parse_yaml("|\r a\r\r b")}; EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), "a\n\nb"); } TEST(tab_after_escaped_line_break) { const auto result{sourcemeta::core::parse_yaml("\"a\\\n\tb\"")}; EXPECT_TRUE(result.is_string()); + EXPECT_EQ(result.to_string(), "ab"); } From 1515a7035e533cb8bb2b8c28dc1e4032855accf3 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 7 Aug 2026 17:20:07 -0300 Subject: [PATCH 3/6] Nicer Signed-off-by: Juan Cruz Viotti --- test/oidc/oidc_discovery_test.cc | 53 ++++++++-------- test/oidc/oidc_registration_test.cc | 93 ++++++++++++++++------------- 2 files changed, 80 insertions(+), 66 deletions(-) diff --git a/test/oidc/oidc_discovery_test.cc b/test/oidc/oidc_discovery_test.cc index 45e8ab2c0d..c32f1cf00a 100644 --- a/test/oidc/oidc_discovery_test.cc +++ b/test/oidc/oidc_discovery_test.cc @@ -301,45 +301,46 @@ TEST(webfinger_issuer_rejects_non_object) { } TEST(webfinger_issuer_rejects_non_array_links) { - EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer( - sourcemeta::core::parse_json(R"({ "links": "x" })")) - .has_value()); + const auto descriptor{ + sourcemeta::core::parse_json(R"JSON({ "links": "x" })JSON")}; + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer(descriptor).has_value()); } TEST(webfinger_issuer_rejects_non_object_link) { - EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer( - sourcemeta::core::parse_json(R"({ "links": [ 123 ] })")) - .has_value()); + const auto descriptor{ + sourcemeta::core::parse_json(R"JSON({ "links": [ 123 ] })JSON")}; + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer(descriptor).has_value()); } TEST(webfinger_issuer_skips_link_without_rel) { - EXPECT_FALSE( - sourcemeta::core::oidc_webfinger_issuer( - sourcemeta::core::parse_json( - R"({ "links": [ { "href": "https://issuer.example.com" } ] })")) - .has_value()); + const auto descriptor{sourcemeta::core::parse_json(R"JSON({ + "links": [ { "href": "https://issuer.example.com" } ] + })JSON")}; + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer(descriptor).has_value()); } TEST(webfinger_issuer_skips_link_with_non_string_rel) { - EXPECT_FALSE( - sourcemeta::core::oidc_webfinger_issuer( - sourcemeta::core::parse_json( - R"({ "links": [ { "rel": 123, "href": "https://issuer.example.com" } ] })")) - .has_value()); + const auto descriptor{sourcemeta::core::parse_json(R"JSON({ + "links": [ { "rel": 123, "href": "https://issuer.example.com" } ] + })JSON")}; + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer(descriptor).has_value()); } TEST(webfinger_issuer_skips_link_with_other_rel) { - EXPECT_FALSE( - sourcemeta::core::oidc_webfinger_issuer( - sourcemeta::core::parse_json( - R"({ "links": [ { "rel": "other", "href": "https://issuer.example.com" } ] })")) - .has_value()); + const auto descriptor{sourcemeta::core::parse_json(R"JSON({ + "links": [ { "rel": "other", "href": "https://issuer.example.com" } ] + })JSON")}; + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer(descriptor).has_value()); } TEST(webfinger_issuer_rejects_matching_rel_with_non_string_href) { - EXPECT_FALSE( - sourcemeta::core::oidc_webfinger_issuer( - sourcemeta::core::parse_json( - R"({ "links": [ { "rel": "http://openid.net/specs/connect/1.0/issuer", "href": 123 } ] })")) - .has_value()); + const auto descriptor{sourcemeta::core::parse_json(R"JSON({ + "links": [ + { + "rel": "http://openid.net/specs/connect/1.0/issuer", + "href": 123 + } + ] + })JSON")}; + EXPECT_FALSE(sourcemeta::core::oidc_webfinger_issuer(descriptor).has_value()); } diff --git a/test/oidc/oidc_registration_test.cc b/test/oidc/oidc_registration_test.cc index 9adc090515..91acc12ba2 100644 --- a/test/oidc/oidc_registration_test.cc +++ b/test/oidc/oidc_registration_test.cc @@ -450,77 +450,90 @@ TEST(encrypted_and_userinfo_algorithm_accessors) { } TEST(from_rejects_non_array_redirect_uris) { - EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from( - sourcemeta::core::parse_json(R"({ "redirect_uris": "x" })")) + auto document{ + sourcemeta::core::parse_json(R"JSON({ "redirect_uris": "x" })JSON")}; + EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from(std::move(document)) .has_value()); } TEST(from_rejects_non_string_redirect_uri_element) { - EXPECT_FALSE( - sourcemeta::core::OIDCClientMetadata::from( - sourcemeta::core::parse_json(R"({ "redirect_uris": [ 123 ] })")) - .has_value()); + auto document{ + sourcemeta::core::parse_json(R"JSON({ "redirect_uris": [ 123 ] })JSON")}; + EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from(std::move(document)) + .has_value()); } TEST(from_rejects_non_string_subject_type) { - EXPECT_FALSE( - sourcemeta::core::OIDCClientMetadata::from( - sourcemeta::core::parse_json( - R"({ "redirect_uris": [ "https://cb.example.com" ], "subject_type": 123 })")) - .has_value()); + auto document{sourcemeta::core::parse_json(R"JSON({ + "redirect_uris": [ "https://cb.example.com" ], + "subject_type": 123 + })JSON")}; + EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from(std::move(document)) + .has_value()); } TEST(from_rejects_non_string_id_token_signed_alg) { - EXPECT_FALSE( - sourcemeta::core::OIDCClientMetadata::from( - sourcemeta::core::parse_json( - R"({ "redirect_uris": [ "https://cb.example.com" ], "id_token_signed_response_alg": 123 })")) - .has_value()); + auto document{sourcemeta::core::parse_json(R"JSON({ + "redirect_uris": [ "https://cb.example.com" ], + "id_token_signed_response_alg": 123 + })JSON")}; + EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from(std::move(document)) + .has_value()); } TEST(from_rejects_non_string_id_token_encrypted_alg) { - EXPECT_FALSE( - sourcemeta::core::OIDCClientMetadata::from( - sourcemeta::core::parse_json( - R"({ "redirect_uris": [ "https://cb.example.com" ], "id_token_encrypted_response_alg": 123 })")) - .has_value()); + auto document{sourcemeta::core::parse_json(R"JSON({ + "redirect_uris": [ "https://cb.example.com" ], + "id_token_encrypted_response_alg": 123 + })JSON")}; + EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from(std::move(document)) + .has_value()); } TEST(from_rejects_non_string_userinfo_signed_alg) { - EXPECT_FALSE( - sourcemeta::core::OIDCClientMetadata::from( - sourcemeta::core::parse_json( - R"({ "redirect_uris": [ "https://cb.example.com" ], "userinfo_signed_response_alg": 123 })")) - .has_value()); + auto document{sourcemeta::core::parse_json(R"JSON({ + "redirect_uris": [ "https://cb.example.com" ], + "userinfo_signed_response_alg": 123 + })JSON")}; + EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from(std::move(document)) + .has_value()); } TEST(from_rejects_non_string_sector_identifier_uri) { - EXPECT_FALSE( - sourcemeta::core::OIDCClientMetadata::from( - sourcemeta::core::parse_json( - R"({ "redirect_uris": [ "https://cb.example.com" ], "sector_identifier_uri": 123 })")) - .has_value()); + auto document{sourcemeta::core::parse_json(R"JSON({ + "redirect_uris": [ "https://cb.example.com" ], + "sector_identifier_uri": 123 + })JSON")}; + EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from(std::move(document)) + .has_value()); } TEST(from_rejects_non_string_initiate_login_uri) { - EXPECT_FALSE( - sourcemeta::core::OIDCClientMetadata::from( - sourcemeta::core::parse_json( - R"({ "redirect_uris": [ "https://cb.example.com" ], "initiate_login_uri": 123 })")) - .has_value()); + auto document{sourcemeta::core::parse_json(R"JSON({ + "redirect_uris": [ "https://cb.example.com" ], + "initiate_login_uri": 123 + })JSON")}; + EXPECT_FALSE(sourcemeta::core::OIDCClientMetadata::from(std::move(document)) + .has_value()); } TEST(from_accepts_valid_initiate_login_uri) { + auto document{sourcemeta::core::parse_json(R"JSON({ + "redirect_uris": [ "https://cb.example.com" ], + "initiate_login_uri": "https://login.example.com" + })JSON")}; const auto metadata{ - sourcemeta::core::OIDCClientMetadata::from(sourcemeta::core::parse_json( - R"({ "redirect_uris": [ "https://cb.example.com" ], "initiate_login_uri": "https://login.example.com" })"))}; + sourcemeta::core::OIDCClientMetadata::from(std::move(document))}; EXPECT_TRUE(metadata.has_value()); } TEST(require_auth_time_false_accessor) { + auto document{sourcemeta::core::parse_json(R"JSON({ + "redirect_uris": [ "https://cb.example.com" ], + "require_auth_time": false + })JSON")}; const auto metadata{ - sourcemeta::core::OIDCClientMetadata::from(sourcemeta::core::parse_json( - R"({ "redirect_uris": [ "https://cb.example.com" ], "require_auth_time": false })"))}; + sourcemeta::core::OIDCClientMetadata::from(std::move(document))}; EXPECT_TRUE(metadata.has_value()); EXPECT_FALSE(metadata.value().require_auth_time()); } From b96b345756b827aa09522f4c4a87b30c176235f7 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 7 Aug 2026 17:25:17 -0300 Subject: [PATCH 4/6] More Signed-off-by: Juan Cruz Viotti --- test/jsonld/jsonld_is_expanded_test.cc | 155 ++++++++++++++++++++----- 1 file changed, 128 insertions(+), 27 deletions(-) diff --git a/test/jsonld/jsonld_is_expanded_test.cc b/test/jsonld/jsonld_is_expanded_test.cc index ca2712ca9b..91ec2f3e04 100644 --- a/test/jsonld/jsonld_is_expanded_test.cc +++ b/test/jsonld/jsonld_is_expanded_test.cc @@ -348,129 +348,230 @@ TEST(reverse_value_not_array) { TEST(value_object_with_type_and_direction_no_language) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ - { "@value": "x", "@type": "http://example.com/t", "@direction": "ltr" } - ] } + { + "http://example.com/p": [ + { + "@value": "x", + "@type": "http://example.com/t", + "@direction": "ltr" + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_non_string_type) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@value": "x", "@type": 123 } ] } + { + "http://example.com/p": [ + { + "@value": "x", + "@type": 123 + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_non_iri_type) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@value": "x", "@type": "notaniri" } ] } + { + "http://example.com/p": [ + { + "@value": "x", + "@type": "notaniri" + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_object_contents_and_type) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ - { "@value": { "a": 1 }, "@type": "http://example.com/t" } - ] } + { + "http://example.com/p": [ + { + "@value": { + "a": 1 + }, + "@type": "http://example.com/t" + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_array_contents_and_type) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ - { "@value": [ 1, 2 ], "@type": "http://example.com/t" } - ] } + { + "http://example.com/p": [ + { + "@value": [ 1, 2 ], + "@type": "http://example.com/t" + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_array_contents_no_type) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@value": [ 1, 2 ] } ] } + { + "http://example.com/p": [ + { + "@value": [ 1, 2 ] + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_non_string_language) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@value": "x", "@language": 123 } ] } + { + "http://example.com/p": [ + { + "@value": "x", + "@language": 123 + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_language_but_non_string_value) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@value": 123, "@language": "en" } ] } + { + "http://example.com/p": [ + { + "@value": 123, + "@language": "en" + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_non_string_direction) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@value": "x", "@direction": 123 } ] } + { + "http://example.com/p": [ + { + "@value": "x", + "@direction": 123 + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_direction_but_non_string_value) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@value": 123, "@direction": "ltr" } ] } + { + "http://example.com/p": [ + { + "@value": 123, + "@direction": "ltr" + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(value_object_with_non_string_index) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@value": "x", "@index": 123 } ] } + { + "http://example.com/p": [ + { + "@value": "x", + "@index": 123 + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(node_with_non_string_index) { - const auto document = - sourcemeta::core::parse_json(R"([ { "@index": 123 } ])"); + const auto document = sourcemeta::core::parse_json(R"([ + { + "@index": 123 + } + ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(node_type_array_with_invalid_reference) { const auto document = sourcemeta::core::parse_json(R"([ - { "@type": [ "bad ref with spaces" ] } + { + "@type": [ "bad ref with spaces" ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(node_with_non_array_graph) { - const auto document = - sourcemeta::core::parse_json(R"([ { "@graph": "x" } ])"); + const auto document = sourcemeta::core::parse_json(R"([ + { + "@graph": "x" + } + ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(node_with_non_object_reverse) { - const auto document = - sourcemeta::core::parse_json(R"([ { "@reverse": "x" } ])"); + const auto document = sourcemeta::core::parse_json(R"([ + { + "@reverse": "x" + } + ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(node_reverse_with_non_iri_key) { const auto document = sourcemeta::core::parse_json(R"([ - { "@reverse": { "notaterm": [] } } + { + "@reverse": { + "notaterm": [] + } + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(list_object_with_non_array_list) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@list": "x" } ] } + { + "http://example.com/p": [ + { + "@list": "x" + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } TEST(list_object_with_non_string_index) { const auto document = sourcemeta::core::parse_json(R"([ - { "http://example.com/p": [ { "@list": [], "@index": 123 } ] } + { + "http://example.com/p": [ + { + "@list": [], + "@index": 123 + } + ] + } ])"); EXPECT_FALSE(sourcemeta::core::jsonld_is_expanded(document)); } From b1cf4716af06cda0bd2eafcfa24a9a0eeb1c050c Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 7 Aug 2026 17:29:31 -0300 Subject: [PATCH 5/6] More Signed-off-by: Juan Cruz Viotti --- test/ip/ipv6_classify_test.cc | 7 +------ test/json/json_value_test.cc | 12 ++++++++---- test/uri/uri_relative_to_test.cc | 13 ------------- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/test/ip/ipv6_classify_test.cc b/test/ip/ipv6_classify_test.cc index 6756e23ac1..b5ffa29a6b 100644 --- a/test/ip/ipv6_classify_test.cc +++ b/test/ip/ipv6_classify_test.cc @@ -242,16 +242,11 @@ TEST(invalid_ipv4) { EXPECT_FALSE(sourcemeta::core::ipv6_classify("127.0.0.1").has_value()); } -TEST(teredo_prefix_nonzero_middle_not_anycast) { +TEST(anycast_block_with_nonzero_interface_is_reserved) { const auto result{sourcemeta::core::ipv6_classify("2001:1:0:0:0:0:100:1")}; EXPECT_EQ(result.value(), sourcemeta::core::IPAddressClass::Reserved); } -TEST(benchmarking_prefix_last_byte_above_three) { - const auto result{sourcemeta::core::ipv6_classify("2001:1::4")}; - EXPECT_EQ(result.value(), sourcemeta::core::IPAddressClass::Reserved); -} - TEST(leading_zero_but_not_mapped_form) { const auto result{sourcemeta::core::ipv6_classify("::100:0:0")}; EXPECT_EQ(result.value(), sourcemeta::core::IPAddressClass::Reserved); diff --git a/test/json/json_value_test.cc b/test/json/json_value_test.cc index 9d6d6279b8..1d360149a9 100644 --- a/test/json/json_value_test.cc +++ b/test/json/json_value_test.cc @@ -867,19 +867,23 @@ TEST(subtract_integer_overflow_promotes_to_decimal) { } TEST(copy_self_assignment) { - sourcemeta::core::JSON value{42}; + sourcemeta::core::JSON value{ + sourcemeta::core::parse_json(R"JSON({ "a": [ 1, 2 ] })JSON")}; const sourcemeta::core::JSON &alias{value}; value = alias; - EXPECT_EQ(value.to_integer(), 42); + EXPECT_EQ(value, + sourcemeta::core::parse_json(R"JSON({ "a": [ 1, 2 ] })JSON")); } TEST(move_self_assignment) { - sourcemeta::core::JSON value{42}; + sourcemeta::core::JSON value{ + sourcemeta::core::parse_json(R"JSON({ "a": [ 1, 2 ] })JSON")}; // Route through a reference so the compiler cannot statically flag the // self-move, while the runtime self-assignment branch is still exercised sourcemeta::core::JSON &alias{value}; value = std::move(alias); - EXPECT_EQ(value.to_integer(), 42); + EXPECT_EQ(value, + sourcemeta::core::parse_json(R"JSON({ "a": [ 1, 2 ] })JSON")); } TEST(null_less_than_null_is_false) { diff --git a/test/uri/uri_relative_to_test.cc b/test/uri/uri_relative_to_test.cc index 580a467434..4b1ebf9982 100644 --- a/test/uri/uri_relative_to_test.cc +++ b/test/uri/uri_relative_to_test.cc @@ -377,19 +377,6 @@ TEST(relative_to_same_path_with_query_in_base) { EXPECT_EQ(target.recompose(), "?bar=1"); } -TEST(relative_to_sibling_directory_yields_empty) { - sourcemeta::core::URI target{"https://example.com/test/"}; - target.relative_to( - sourcemeta::core::URI{"https://example.com/test/foo.json"}); - EXPECT_EQ(target.recompose(), ""); -} - -TEST(relative_to_root_from_authority_yields_empty) { - sourcemeta::core::URI target{"https://example.com/"}; - target.relative_to(sourcemeta::core::URI{"https://example.com"}); - EXPECT_EQ(target.recompose(), ""); -} - TEST(relative_to_slashless_base_path) { sourcemeta::core::URI target{"schema:bar"}; target.relative_to(sourcemeta::core::URI{"schema:foo"}); From 9930c5e135ff4601353d36115c095a16a46b226a Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Fri, 7 Aug 2026 17:39:34 -0300 Subject: [PATCH 6/6] Fix Signed-off-by: Juan Cruz Viotti --- test/json/json_value_test.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/json/json_value_test.cc b/test/json/json_value_test.cc index 1d360149a9..bcde80a374 100644 --- a/test/json/json_value_test.cc +++ b/test/json/json_value_test.cc @@ -1,10 +1,11 @@ #include #include -#include // std::size_t -#include +#include // std::size_t +#include // std::int64_t #include // std::reference_wrapper -#include // std::int64_t +#include // std::numeric_limits +#include // std::out_of_range #include // std::string #include // std::is_default_constructible, etc #include // std::unordered_map