From 04ec2bb37d5bfd2bb28fffbfe58401a3ccd5d9a9 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 17 Mar 2026 13:01:43 -0400 Subject: [PATCH] Implement a `sourcemeta::core::is_pointer` convenience function Signed-off-by: Juan Cruz Viotti --- .../include/sourcemeta/core/jsonpointer.h | 15 +++ src/core/jsonpointer/jsonpointer.cc | 13 ++- src/core/jsonpointer/parser.h | 94 +++++++++++++------ .../jsonpointer_parse_error_test.cc | 85 +++++++++++++++++ test/jsonpointer/jsonpointer_parse_test.cc | 67 +++++++++++++ 5 files changed, 243 insertions(+), 31 deletions(-) diff --git a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer.h b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer.h index 2f2e16c0c..56885d9fb 100644 --- a/src/core/jsonpointer/include/sourcemeta/core/jsonpointer.h +++ b/src/core/jsonpointer/include/sourcemeta/core/jsonpointer.h @@ -423,6 +423,21 @@ auto to_pointer(const std::basic_string Pointer; +/// @ingroup jsonpointer +/// Check if the given string is a valid JSON Pointer per RFC 6901 without +/// constructing a JSON Pointer object. For example: +/// +/// ```cpp +/// #include +/// #include +/// +/// assert(sourcemeta::core::is_pointer("/foo/bar/0")); +/// assert(sourcemeta::core::is_pointer("")); +/// assert(!sourcemeta::core::is_pointer("foo")); +/// ``` +SOURCEMETA_CORE_JSONPOINTER_EXPORT +auto is_pointer(std::string_view input) noexcept -> bool; + /// @ingroup jsonpointer /// Convert a JSON Pointer into a JSON WeakPointer. For example: /// diff --git a/src/core/jsonpointer/jsonpointer.cc b/src/core/jsonpointer/jsonpointer.cc index 794e8b46e..70be9a264 100644 --- a/src/core/jsonpointer/jsonpointer.cc +++ b/src/core/jsonpointer/jsonpointer.cc @@ -15,6 +15,7 @@ #include // std::basic_ostream #include // std::basic_ostringstream, std::basic_stringstream #include // std::basic_string +#include // std::string_view #include // std::is_same_v #include // std::move @@ -302,7 +303,7 @@ auto remove(JSON &document, const WeakPointer &pointer) -> bool { auto to_pointer(const JSON &document) -> Pointer { assert(document.is_string()); auto stream{document.to_stringstream()}; - return parse_pointer(stream); + return parse_pointer(stream); } auto to_pointer(const std::basic_string URI { return to_uri(pointer).resolve_from(URI{base}).canonicalize(); } +auto is_pointer(const std::string_view input) noexcept -> bool { + try { + std::basic_istringstream stream{std::string{input}}; + parse_pointer(stream); + return true; + } catch (...) { + return false; + } +} + } // namespace sourcemeta::core diff --git a/src/core/jsonpointer/parser.h b/src/core/jsonpointer/parser.h index 35a5615d9..d0bc7f658 100644 --- a/src/core/jsonpointer/parser.h +++ b/src/core/jsonpointer/parser.h @@ -7,11 +7,12 @@ #include #include -#include // std::uint64_t -#include // std::basic_istream -#include // std::basic_stringstream -#include // std::out_of_range -#include // std::stoi +#include // std::uint64_t +#include // std::basic_istream +#include // std::basic_stringstream +#include // std::out_of_range +#include // std::stoi +#include // std::conditional_t namespace sourcemeta::core::internal { template > &stream, // NOLINTBEGIN(cppcoreguidelines-avoid-goto) namespace sourcemeta::core { +template auto parse_pointer(std::basic_istream &stream) - -> Pointer { - Pointer result; + -> std::conditional_t { + [[maybe_unused]] Pointer result; JSON::Char character = 0; - std::basic_stringstream string; + [[maybe_unused]] std::basic_stringstream string; std::uint64_t column{0}; parse_token_begin: @@ -84,15 +86,21 @@ auto parse_pointer(std::basic_istream &stream) case internal::token_pointer_number_nine: column += 1; stream.ignore(); - string.put(character); + if constexpr (!CheckOnly) { + string.put(character); + } goto parse_token_index_rest_any; case static_cast(JSON::CharTraits::eof()): column += 1; stream.ignore(); - result.emplace_back(""); + if constexpr (!CheckOnly) { + result.emplace_back(""); + } goto done; case internal::token_pointer_slash: - result.emplace_back(""); + if constexpr (!CheckOnly) { + result.emplace_back(""); + } goto parse_token_begin; case internal::token_pointer_tilde: column += 1; @@ -101,7 +109,9 @@ auto parse_pointer(std::basic_istream &stream) default: column += 1; stream.ignore(); - string.put(character); + if constexpr (!CheckOnly) { + string.put(character); + } goto parse_token_property_rest_any; } @@ -110,20 +120,26 @@ auto parse_pointer(std::basic_istream &stream) */ parse_token_index_end: - string.put(character); + if constexpr (!CheckOnly) { + string.put(character); + } character = static_cast(stream.peek()); switch (character) { case internal::token_pointer_slash: column += 1; stream.ignore(); - result.emplace_back(internal::parse_index(string, column)); - internal::reset(string); + if constexpr (!CheckOnly) { + result.emplace_back(internal::parse_index(string, column)); + internal::reset(string); + } goto parse_token_content; case static_cast(JSON::CharTraits::eof()): column += 1; stream.ignore(); - result.emplace_back(internal::parse_index(string, column)); - internal::reset(string); + if constexpr (!CheckOnly) { + result.emplace_back(internal::parse_index(string, column)); + internal::reset(string); + } goto done; default: goto parse_token_property_rest_any; @@ -135,14 +151,18 @@ auto parse_pointer(std::basic_istream &stream) case internal::token_pointer_slash: column += 1; stream.ignore(); - result.emplace_back(internal::parse_index(string, column)); - internal::reset(string); + if constexpr (!CheckOnly) { + result.emplace_back(internal::parse_index(string, column)); + internal::reset(string); + } goto parse_token_content; case static_cast(JSON::CharTraits::eof()): column += 1; stream.ignore(); - result.emplace_back(internal::parse_index(string, column)); - internal::reset(string); + if constexpr (!CheckOnly) { + result.emplace_back(internal::parse_index(string, column)); + internal::reset(string); + } goto done; case internal::token_pointer_number_zero: case internal::token_pointer_number_one: @@ -156,7 +176,9 @@ auto parse_pointer(std::basic_istream &stream) case internal::token_pointer_number_nine: column += 1; stream.ignore(); - string.put(character); + if constexpr (!CheckOnly) { + string.put(character); + } goto parse_token_index_rest_any; default: @@ -172,17 +194,23 @@ auto parse_pointer(std::basic_istream &stream) column += 1; switch (character) { case internal::token_pointer_slash: - result.emplace_back(string.str()); - internal::reset(string); + if constexpr (!CheckOnly) { + result.emplace_back(string.str()); + internal::reset(string); + } goto parse_token_content; case internal::token_pointer_tilde: goto parse_token_escape_tilde; case static_cast(JSON::CharTraits::eof()): - result.emplace_back(string.str()); - internal::reset(string); + if constexpr (!CheckOnly) { + result.emplace_back(string.str()); + internal::reset(string); + } goto done; default: - string.put(character); + if constexpr (!CheckOnly) { + string.put(character); + } goto parse_token_property_rest_any; } @@ -196,17 +224,23 @@ auto parse_pointer(std::basic_istream &stream) // See https://www.rfc-editor.org/rfc/rfc6901#section-3 switch (character) { case internal::token_pointer_number_zero: - string.put(internal::token_pointer_tilde); + if constexpr (!CheckOnly) { + string.put(internal::token_pointer_tilde); + } goto parse_token_property_rest_any; case internal::token_pointer_number_one: - string.put(internal::token_pointer_slash); + if constexpr (!CheckOnly) { + string.put(internal::token_pointer_slash); + } goto parse_token_property_rest_any; default: throw PointerParseError(column); } done: - return result; + if constexpr (!CheckOnly) { + return result; + } } // NOLINTEND(cppcoreguidelines-avoid-goto) diff --git a/test/jsonpointer/jsonpointer_parse_error_test.cc b/test/jsonpointer/jsonpointer_parse_error_test.cc index 8fdff3873..0af59c8d6 100644 --- a/test/jsonpointer/jsonpointer_parse_error_test.cc +++ b/test/jsonpointer/jsonpointer_parse_error_test.cc @@ -33,76 +33,92 @@ TEST(JSONPointer_parse_error, missing_initial_slash) { const std::string input{"1"}; EXPECT_POINTER_PARSE_ERROR(input, 1); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, tilde) { const std::string input{"/~"}; EXPECT_POINTER_PARSE_ERROR(input, 3); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, tilde_2) { const std::string input{"/~2"}; EXPECT_POINTER_PARSE_ERROR(input, 3); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, tilde_tilde) { const std::string input{"/~~"}; EXPECT_POINTER_PARSE_ERROR(input, 3); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, foo_tilde) { const std::string input{"/foo~"}; EXPECT_POINTER_PARSE_ERROR(input, 6); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, index_foo_tilde) { const std::string input{"/123/foo~"}; EXPECT_POINTER_PARSE_ERROR(input, 10); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, zero_index_foo_tilde) { const std::string input{"/0/foo~"}; EXPECT_POINTER_PARSE_ERROR(input, 8); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, slash_slash_foo_tilde) { const std::string input{"//foo~"}; EXPECT_POINTER_PARSE_ERROR(input, 7); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, foo_tilde_2) { const std::string input{"/foo~2"}; EXPECT_POINTER_PARSE_ERROR(input, 6); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, foo_tilde_tilde) { const std::string input{"/foo~~"}; EXPECT_POINTER_PARSE_ERROR(input, 6); + EXPECT_FALSE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, backspace) { const std::string input{"/\b"}; EXPECT_JSON_PARSE_ERROR(input); + // RFC 6901: control characters are valid in unescaped production + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, formfeed) { const std::string input{"/\f"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, newline) { const std::string input{"/\n"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, carriage_return) { const std::string input{"/\r"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, tab) { const std::string input{"/\t"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, null) { @@ -110,31 +126,37 @@ TEST(JSONPointer_parse_error, null) { using namespace std::string_literals; const std::string input{"/\0"s}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, backspace_within_word) { const std::string input{"/foo\bbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, formfeed_within_word) { const std::string input{"/foo\fbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, newline_within_word) { const std::string input{"/foo\nbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, carriage_return_within_word) { const std::string input{"/foo\rbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, tab_within_word) { const std::string input{"/foo\tbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, null_within_word) { @@ -142,314 +164,377 @@ TEST(JSONPointer_parse_error, null_within_word) { using namespace std::string_literals; const std::string input{"/foo\0bar"s}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0001) { const std::string input{"/\u0001"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0002) { const std::string input{"/\u0002"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0003) { const std::string input{"/\u0003"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0004) { const std::string input{"/\u0004"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0005) { const std::string input{"/\u0005"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0006) { const std::string input{"/\u0006"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0007) { const std::string input{"/\u0007"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0008) { const std::string input{"/\u0008"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0009) { const std::string input{"/\u0009"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000A) { const std::string input{"/\u000A"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000B) { const std::string input{"/\u000B"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000C) { const std::string input{"/\u000C"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000D) { const std::string input{"/\u000D"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000E) { const std::string input{"/\u000E"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000F) { const std::string input{"/\u000F"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0010) { const std::string input{"/\u0010"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0011) { const std::string input{"/\u0011"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0012) { const std::string input{"/\u0012"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0013) { const std::string input{"/\u0013"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0014) { const std::string input{"/\u0014"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0015) { const std::string input{"/\u0015"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0016) { const std::string input{"/\u0016"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0017) { const std::string input{"/\u0017"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0018) { const std::string input{"/\u0018"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0019) { const std::string input{"/\u0019"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001A) { const std::string input{"/\u001A"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001B) { const std::string input{"/\u001B"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001C) { const std::string input{"/\u001C"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001D) { const std::string input{"/\u001D"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001E) { const std::string input{"/\u001E"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001F) { const std::string input{"/\u001F"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0001_within_word) { const std::string input{"/foo\u0001bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0002_within_word) { const std::string input{"/foo\u0002bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0003_within_word) { const std::string input{"/foo\u0003bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0004_within_word) { const std::string input{"/foo\u0004bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0005_within_word) { const std::string input{"/foo\u0005bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0006_within_word) { const std::string input{"/foo\u0006bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0007_within_word) { const std::string input{"/foo\u0007bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0008_within_word) { const std::string input{"/foo\u0008bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0009_within_word) { const std::string input{"/foo\u0009bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000A_within_word) { const std::string input{"/foo\u000Abar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000B_within_word) { const std::string input{"/foo\u000Bbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000C_within_word) { const std::string input{"/foo\u000Cbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000D_within_word) { const std::string input{"/foo\u000Dbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000E_within_word) { const std::string input{"/foo\u000Ebar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_000F_within_word) { const std::string input{"/foo\u000Fbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0010_within_word) { const std::string input{"/foo\u0010bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0011_within_word) { const std::string input{"/foo\u0011bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0012_within_word) { const std::string input{"/foo\u0012bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0013_within_word) { const std::string input{"/foo\u0013bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0014_within_word) { const std::string input{"/foo\u0014bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0015_within_word) { const std::string input{"/foo\u0015bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0016_within_word) { const std::string input{"/foo\u0016bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0017_within_word) { const std::string input{"/foo\u0017bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0018_within_word) { const std::string input{"/foo\u0018bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_0019_within_word) { const std::string input{"/foo\u0019bar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001A_within_word) { const std::string input{"/foo\u001Abar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001B_within_word) { const std::string input{"/foo\u001Bbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001C_within_word) { const std::string input{"/foo\u001Cbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001D_within_word) { const std::string input{"/foo\u001Dbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001E_within_word) { const std::string input{"/foo\u001Ebar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } TEST(JSONPointer_parse_error, unicode_001F_within_word) { const std::string input{"/foo\u001Fbar"}; EXPECT_JSON_PARSE_ERROR(input); + EXPECT_TRUE(sourcemeta::core::is_pointer(input)); } diff --git a/test/jsonpointer/jsonpointer_parse_test.cc b/test/jsonpointer/jsonpointer_parse_test.cc index 244202e53..935e87ca5 100644 --- a/test/jsonpointer/jsonpointer_parse_test.cc +++ b/test/jsonpointer/jsonpointer_parse_test.cc @@ -7,11 +7,13 @@ #include TEST(JSONPointer_parse, empty_string) { + EXPECT_TRUE(sourcemeta::core::is_pointer("")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer(""); EXPECT_EQ(pointer.size(), 0); } TEST(JSONPointer_parse, slash) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_property()); @@ -19,6 +21,7 @@ TEST(JSONPointer_parse, slash) { } TEST(JSONPointer_parse, slash_f) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/f")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/f"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_property()); @@ -26,6 +29,7 @@ TEST(JSONPointer_parse, slash_f) { } TEST(JSONPointer_parse, slash_foo) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo"); EXPECT_EQ(pointer.size(), 1); @@ -34,6 +38,7 @@ TEST(JSONPointer_parse, slash_foo) { } TEST(JSONPointer_parse, slash_foo_bar_baz) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo/bar/baz")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo/bar/baz"); EXPECT_EQ(pointer.size(), 3); @@ -46,6 +51,7 @@ TEST(JSONPointer_parse, slash_foo_bar_baz) { } TEST(JSONPointer_parse, slash_0) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/0")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/0"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_index()); @@ -53,6 +59,7 @@ TEST(JSONPointer_parse, slash_0) { } TEST(JSONPointer_parse, slash_1) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/1")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/1"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_index()); @@ -60,6 +67,7 @@ TEST(JSONPointer_parse, slash_1) { } TEST(JSONPointer_parse, slash_1234) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/1234")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/1234"); EXPECT_EQ(pointer.size(), 1); @@ -68,6 +76,7 @@ TEST(JSONPointer_parse, slash_1234) { } TEST(JSONPointer_parse, slash_0_slash_1_slash_2) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/0/1/2")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/0/1/2"); EXPECT_EQ(pointer.size(), 3); @@ -80,6 +89,7 @@ TEST(JSONPointer_parse, slash_0_slash_1_slash_2) { } TEST(JSONPointer_parse, slash_0_slash_foo_slash_2) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/0/foo/2")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/0/foo/2"); EXPECT_EQ(pointer.size(), 3); @@ -92,6 +102,7 @@ TEST(JSONPointer_parse, slash_0_slash_foo_slash_2) { } TEST(JSONPointer_parse, slash_0_slash_1234) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/0/1234")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/0/1234"); EXPECT_EQ(pointer.size(), 2); @@ -102,6 +113,7 @@ TEST(JSONPointer_parse, slash_0_slash_1234) { } TEST(JSONPointer_parse, slash_1000) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/1000")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/1000"); EXPECT_EQ(pointer.size(), 1); @@ -110,6 +122,7 @@ TEST(JSONPointer_parse, slash_1000) { } TEST(JSONPointer_parse, negative_index_as_property) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/-1")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/-1"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_property()); @@ -117,6 +130,7 @@ TEST(JSONPointer_parse, negative_index_as_property) { } TEST(JSONPointer_parse, slash_space_integer) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/ 12")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/ 12"); EXPECT_EQ(pointer.size(), 1); @@ -125,6 +139,7 @@ TEST(JSONPointer_parse, slash_space_integer) { } TEST(JSONPointer_parse, slash_foo_slash_space_integer) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo/ 12")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo/ 12"); EXPECT_EQ(pointer.size(), 2); @@ -135,6 +150,7 @@ TEST(JSONPointer_parse, slash_foo_slash_space_integer) { } TEST(JSONPointer_parse, slash_foo_slash_space_bar_space) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo/ bar ")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo/ bar "); EXPECT_EQ(pointer.size(), 2); @@ -145,6 +161,7 @@ TEST(JSONPointer_parse, slash_foo_slash_space_bar_space) { } TEST(JSONPointer_parse, slash_f_slash) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/f/")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/f/"); EXPECT_EQ(pointer.size(), 2); EXPECT_TRUE(pointer.at(0).is_property()); @@ -154,6 +171,7 @@ TEST(JSONPointer_parse, slash_f_slash) { } TEST(JSONPointer_parse, slash_slash) { + EXPECT_TRUE(sourcemeta::core::is_pointer("//")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("//"); EXPECT_EQ(pointer.size(), 2); EXPECT_TRUE(pointer.at(0).is_property()); @@ -163,6 +181,7 @@ TEST(JSONPointer_parse, slash_slash) { } TEST(JSONPointer_parse, slash_slash_slash) { + EXPECT_TRUE(sourcemeta::core::is_pointer("///")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("///"); EXPECT_EQ(pointer.size(), 3); EXPECT_TRUE(pointer.at(0).is_property()); @@ -174,6 +193,7 @@ TEST(JSONPointer_parse, slash_slash_slash) { } TEST(JSONPointer_parse, slash_slash_slash_foo) { + EXPECT_TRUE(sourcemeta::core::is_pointer("///foo")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("///foo"); EXPECT_EQ(pointer.size(), 3); @@ -186,6 +206,7 @@ TEST(JSONPointer_parse, slash_slash_slash_foo) { } TEST(JSONPointer_parse, positive_hex_index) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/0x23")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/0x23"); EXPECT_EQ(pointer.size(), 1); @@ -194,6 +215,7 @@ TEST(JSONPointer_parse, positive_hex_index) { } TEST(JSONPointer_parse, slash_00) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/00")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/00"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_property()); @@ -201,6 +223,7 @@ TEST(JSONPointer_parse, slash_00) { } TEST(JSONPointer_parse, slash_01) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/01")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/01"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_property()); @@ -208,6 +231,7 @@ TEST(JSONPointer_parse, slash_01) { } TEST(JSONPointer_parse, slash_001) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/001")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/001"); EXPECT_EQ(pointer.size(), 1); @@ -216,6 +240,7 @@ TEST(JSONPointer_parse, slash_001) { } TEST(JSONPointer_parse, slash_0100) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/0100")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/0100"); EXPECT_EQ(pointer.size(), 1); @@ -224,6 +249,7 @@ TEST(JSONPointer_parse, slash_0100) { } TEST(JSONPointer_parse, positive_real_number_index) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/1.23")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/1.23"); EXPECT_EQ(pointer.size(), 1); @@ -232,6 +258,7 @@ TEST(JSONPointer_parse, positive_real_number_index) { } TEST(JSONPointer_parse, index_in_scientific_notation) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/1e1")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/1e1"); EXPECT_EQ(pointer.size(), 1); @@ -240,6 +267,7 @@ TEST(JSONPointer_parse, index_in_scientific_notation) { } TEST(JSONPointer_parse, integer_with_space) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/1 1")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/1 1"); EXPECT_EQ(pointer.size(), 1); @@ -248,6 +276,7 @@ TEST(JSONPointer_parse, integer_with_space) { } TEST(JSONPointer_parse, percentage) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/c%d")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/c%d"); EXPECT_EQ(pointer.size(), 1); @@ -256,6 +285,7 @@ TEST(JSONPointer_parse, percentage) { } TEST(JSONPointer_parse, caret) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/e^f")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/e^f"); EXPECT_EQ(pointer.size(), 1); @@ -264,6 +294,7 @@ TEST(JSONPointer_parse, caret) { } TEST(JSONPointer_parse, pipe) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/g|h")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/g|h"); EXPECT_EQ(pointer.size(), 1); @@ -272,6 +303,7 @@ TEST(JSONPointer_parse, pipe) { } TEST(JSONPointer_parse, backslash_after_letter) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/i\\\\j")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/i\\\\j"); EXPECT_EQ(pointer.size(), 1); @@ -280,6 +312,7 @@ TEST(JSONPointer_parse, backslash_after_letter) { } TEST(JSONPointer_parse, backslash) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\\\")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\\\"); EXPECT_EQ(pointer.size(), 1); @@ -288,6 +321,7 @@ TEST(JSONPointer_parse, backslash) { } TEST(JSONPointer_parse, double_quote_after_letter) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/k\\\"l")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/k\\\"l"); EXPECT_EQ(pointer.size(), 1); @@ -296,6 +330,7 @@ TEST(JSONPointer_parse, double_quote_after_letter) { } TEST(JSONPointer_parse, double_quote) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\\"")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\\""); EXPECT_EQ(pointer.size(), 1); @@ -304,6 +339,7 @@ TEST(JSONPointer_parse, double_quote) { } TEST(JSONPointer_parse, space) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/ ")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/ "); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_property()); @@ -311,6 +347,7 @@ TEST(JSONPointer_parse, space) { } TEST(JSONPointer_parse, escaped_slash_after_letter) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/a~1b")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/a~1b"); EXPECT_EQ(pointer.size(), 1); @@ -319,6 +356,7 @@ TEST(JSONPointer_parse, escaped_slash_after_letter) { } TEST(JSONPointer_parse, escaped_slash) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/~1")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/~1"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_property()); @@ -326,6 +364,7 @@ TEST(JSONPointer_parse, escaped_slash) { } TEST(JSONPointer_parse, escaped_slash_with_backslash) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\\\/")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\\\/"); EXPECT_EQ(pointer.size(), 2); @@ -336,6 +375,7 @@ TEST(JSONPointer_parse, escaped_slash_with_backslash) { } TEST(JSONPointer_parse, escaped_slash_with_backslash_after_letter) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/x\\\\/")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/x\\\\/"); EXPECT_EQ(pointer.size(), 2); @@ -346,6 +386,7 @@ TEST(JSONPointer_parse, escaped_slash_with_backslash_after_letter) { } TEST(JSONPointer_parse, escaped_tilde_after_letter) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/m~0n")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/m~0n"); EXPECT_EQ(pointer.size(), 1); @@ -354,6 +395,7 @@ TEST(JSONPointer_parse, escaped_tilde_after_letter) { } TEST(JSONPointer_parse, escaped_tilde) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/~0")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/~0"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_property()); @@ -361,6 +403,7 @@ TEST(JSONPointer_parse, escaped_tilde) { } TEST(JSONPointer_parse, tilde_zero_one) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/~01")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/~01"); EXPECT_EQ(pointer.size(), 1); @@ -369,6 +412,7 @@ TEST(JSONPointer_parse, tilde_zero_one) { } TEST(JSONPointer_parse, tilde_zero_one_after_letter) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/x~01")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/x~01"); EXPECT_EQ(pointer.size(), 1); @@ -377,6 +421,7 @@ TEST(JSONPointer_parse, tilde_zero_one_after_letter) { } TEST(JSONPointer_parse, hyphen) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/-")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/-"); EXPECT_EQ(pointer.size(), 1); EXPECT_TRUE(pointer.at(0).is_hyphen()); @@ -385,6 +430,7 @@ TEST(JSONPointer_parse, hyphen) { } TEST(JSONPointer_parse, hyphen_hyphen) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/--")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/--"); EXPECT_EQ(pointer.size(), 1); EXPECT_FALSE(pointer.at(0).is_hyphen()); @@ -393,6 +439,7 @@ TEST(JSONPointer_parse, hyphen_hyphen) { } TEST(JSONPointer_parse, hyphen_slash_hyphen) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/-/-")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/-/-"); EXPECT_EQ(pointer.size(), 2); @@ -405,6 +452,7 @@ TEST(JSONPointer_parse, hyphen_slash_hyphen) { } TEST(JSONPointer_parse, escaped_quote_within_string) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo\\\"bar")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo\\\"bar"); EXPECT_EQ(pointer.size(), 1); @@ -413,6 +461,7 @@ TEST(JSONPointer_parse, escaped_quote_within_string) { } TEST(JSONPointer_parse, escaped_quote) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\\"")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\\""); EXPECT_EQ(pointer.size(), 1); @@ -421,6 +470,7 @@ TEST(JSONPointer_parse, escaped_quote) { } TEST(JSONPointer_parse, escaped_backslash_within_string) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo\\\\bar")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo\\\\bar"); EXPECT_EQ(pointer.size(), 1); @@ -429,6 +479,7 @@ TEST(JSONPointer_parse, escaped_backslash_within_string) { } TEST(JSONPointer_parse, escaped_backslash) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\\\")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\\\"); EXPECT_EQ(pointer.size(), 1); @@ -437,6 +488,7 @@ TEST(JSONPointer_parse, escaped_backslash) { } TEST(JSONPointer_parse, control_backslash_backspace) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\b")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\b"); EXPECT_EQ(pointer.size(), 1); @@ -445,6 +497,7 @@ TEST(JSONPointer_parse, control_backslash_backspace) { } TEST(JSONPointer_parse, control_backslash_backspace_within_string) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo\\bbar")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo\\bbar"); EXPECT_EQ(pointer.size(), 1); @@ -453,6 +506,7 @@ TEST(JSONPointer_parse, control_backslash_backspace_within_string) { } TEST(JSONPointer_parse, control_backslash_formfeed) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\f")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\f"); EXPECT_EQ(pointer.size(), 1); @@ -461,6 +515,7 @@ TEST(JSONPointer_parse, control_backslash_formfeed) { } TEST(JSONPointer_parse, control_backslash_formfeed_within_string) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo\\fbar")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo\\fbar"); EXPECT_EQ(pointer.size(), 1); @@ -469,6 +524,7 @@ TEST(JSONPointer_parse, control_backslash_formfeed_within_string) { } TEST(JSONPointer_parse, control_backslash_newline) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\n")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\n"); EXPECT_EQ(pointer.size(), 1); @@ -477,6 +533,7 @@ TEST(JSONPointer_parse, control_backslash_newline) { } TEST(JSONPointer_parse, control_backslash_newline_within_string) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo\\nbar")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo\\nbar"); EXPECT_EQ(pointer.size(), 1); @@ -485,6 +542,7 @@ TEST(JSONPointer_parse, control_backslash_newline_within_string) { } TEST(JSONPointer_parse, control_backslash_carriage) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\r")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\r"); EXPECT_EQ(pointer.size(), 1); @@ -493,6 +551,7 @@ TEST(JSONPointer_parse, control_backslash_carriage) { } TEST(JSONPointer_parse, control_backslash_carriage_within_string) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo\\rbar")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo\\rbar"); EXPECT_EQ(pointer.size(), 1); @@ -501,6 +560,7 @@ TEST(JSONPointer_parse, control_backslash_carriage_within_string) { } TEST(JSONPointer_parse, control_backslash_tab) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/\\t")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/\\t"); EXPECT_EQ(pointer.size(), 1); @@ -509,6 +569,7 @@ TEST(JSONPointer_parse, control_backslash_tab) { } TEST(JSONPointer_parse, control_backslash_tab_within_string) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo\\tbar")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo\\tbar"); EXPECT_EQ(pointer.size(), 1); @@ -517,6 +578,7 @@ TEST(JSONPointer_parse, control_backslash_tab_within_string) { } TEST(JSONPointer_parse, property_with_unicode_code_point) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/foo\\u002Abar")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/foo\\u002Abar"); EXPECT_EQ(pointer.size(), 1); @@ -525,6 +587,9 @@ TEST(JSONPointer_parse, property_with_unicode_code_point) { } TEST(JSONPointer_parse, unicode_slashes) { + // The raw string starts with '\', not '/' - invalid per RFC 6901. + // to_pointer() succeeds because the JSON parser interprets \u002F as '/' + EXPECT_FALSE(sourcemeta::core::is_pointer("\\u002Ffoo\\u002Fbar")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("\\u002Ffoo\\u002Fbar"); EXPECT_EQ(pointer.size(), 2); @@ -535,6 +600,7 @@ TEST(JSONPointer_parse, unicode_slashes) { } TEST(JSONPointer_parse, regex_caret) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/patternProperties/^v/foo")); const sourcemeta::core::Pointer pointer = sourcemeta::core::to_pointer("/patternProperties/^v/foo"); EXPECT_EQ(pointer.size(), 3); @@ -547,6 +613,7 @@ TEST(JSONPointer_parse, regex_caret) { } TEST(JSONPointer_parse, regex_backslash) { + EXPECT_TRUE(sourcemeta::core::is_pointer("/[\\\\-]")); const sourcemeta::core::Pointer pointer = // Needs escaping because here we are interpreting as a C string and not // as a JSON string