diff --git a/src/core/regex/include/sourcemeta/core/regex.h b/src/core/regex/include/sourcemeta/core/regex.h index c2eac823f..49b6625fc 100644 --- a/src/core/regex/include/sourcemeta/core/regex.h +++ b/src/core/regex/include/sourcemeta/core/regex.h @@ -119,6 +119,22 @@ SOURCEMETA_CORE_REGEX_EXPORT auto matches_if_valid(const std::string_view pattern, const std::string_view value) -> bool; +/// @ingroup regex +/// +/// Check whether the given string is a valid ECMA-262 regular expression. For +/// example: +/// +/// ```cpp +/// #include +/// #include +/// +/// assert(sourcemeta::core::is_regex_ecma("([abc])+\\s+$")); +/// assert(!sourcemeta::core::is_regex_ecma("^(abc]")); +/// assert(!sourcemeta::core::is_regex_ecma("\\a")); +/// ``` +SOURCEMETA_CORE_REGEX_EXPORT +auto is_regex_ecma(const std::string_view pattern) -> bool; + } // namespace sourcemeta::core #endif diff --git a/src/core/regex/preprocess.h b/src/core/regex/preprocess.h index 682aac0a9..c9630da45 100644 --- a/src/core/regex/preprocess.h +++ b/src/core/regex/preprocess.h @@ -7,6 +7,7 @@ #include // std::optional #include // std::string #include // std::string_view +#include // std::conditional_t #include // std::pair namespace sourcemeta::core { @@ -636,14 +637,63 @@ inline auto find_shorthand(char escape) -> const ShorthandExpansion * { } // namespace +template inline auto preprocess_regex(const std::string &pattern) - -> std::optional { + -> std::conditional_t> { std::string result; - result.reserve(pattern.size() * 2); + if constexpr (!CheckECMA) { + result.reserve(pattern.size() * 2); + } bool in_class = false; for (std::size_t position = 0; position < pattern.size(); ++position) { const char current = pattern[position]; + + // Reject group constructs that are not part of ECMA-262 + if (current == '(' && !is_escaped(pattern, position) && !in_class && + position + 1 < pattern.size()) { + // (*...) backtracking control verbs (PCRE-only) + if (pattern[position + 1] == '*') { + if constexpr (CheckECMA) { + return false; + } else { + return std::nullopt; + } + } + // (?X...): ECMA only allows (?: (?= (?! (?<= (? + if (pattern[position + 1] == '?' && position + 2 < pattern.size()) { + const char third = pattern[position + 2]; + bool valid_extension{third == ':' || third == '=' || third == '!'}; + if (!valid_extension && third == '<' && position + 3 < pattern.size()) { + const char fourth = pattern[position + 3]; + valid_extension = fourth == '=' || fourth == '!' || + (fourth >= 'a' && fourth <= 'z') || + (fourth >= 'A' && fourth <= 'Z') || fourth == '_' || + fourth == '$'; + } + if (!valid_extension) { + if constexpr (CheckECMA) { + return false; + } else { + return std::nullopt; + } + } + } + } + + // Reject possessive quantifiers (PCRE-only): *+ ++ ?+ + if (current == '+' && position > 0 && !in_class) { + const char prev = pattern[position - 1]; + if ((prev == '*' || prev == '+' || prev == '?') && + !is_escaped(pattern, position - 1)) { + if constexpr (CheckECMA) { + return false; + } else { + return std::nullopt; + } + } + } + if (current == '[' && !is_escaped(pattern, position) && !in_class) { // Find end both ways and check which applies const auto simple_end = find_bracket_end(pattern, position + 1, false); @@ -652,6 +702,16 @@ inline auto preprocess_regex(const std::string &pattern) const auto nested_content = pattern.substr(position + 1, nested_end - position - 2); + // Reject POSIX-style character classes like [[:alpha:]] (PCRE-only) + if (nested_content.size() >= 4 && nested_content[0] == '[' && + nested_content[1] == ':' && nested_content.ends_with(":]")) { + if constexpr (CheckECMA) { + return false; + } else { + return std::nullopt; + } + } + // Check for v-flag operators in nested content const bool nested_has_ops = nested_content.contains("--") || nested_content.contains("&&"); @@ -680,10 +740,16 @@ inline auto preprocess_regex(const std::string &pattern) if (use_v_flag) { const auto expanded = expand_char_class(nested_content); if (!expanded) { - return std::nullopt; + if constexpr (CheckECMA) { + return false; + } else { + return std::nullopt; + } } - result += *expanded; + if constexpr (!CheckECMA) { + result += *expanded; + } position = nested_end - 1; continue; } @@ -696,41 +762,81 @@ inline auto preprocess_regex(const std::string &pattern) } if (current != '\\' || position + 1 >= pattern.size()) { - result += current; + if constexpr (!CheckECMA) { + result += current; + } continue; } const char next = pattern[position + 1]; if (std::string_view{"\\[]^$"}.contains(next)) { - result += current; - result += next; + if constexpr (!CheckECMA) { + result += current; + result += next; + } ++position; continue; } if (next == 'u' && position + 2 < pattern.size()) { if (pattern[position + 2] == '{') { - result += "\\x{"; + if constexpr (!CheckECMA) { + result += "\\x{"; + } for (position += 3; position < pattern.size() && pattern[position] != '}'; ++position) { - result += pattern[position]; + if constexpr (!CheckECMA) { + result += pattern[position]; + } } if (position < pattern.size()) { - result += '}'; + if constexpr (!CheckECMA) { + result += '}'; + } } continue; } if (position + 5 < pattern.size() && all_hex(pattern, position + 2, 4)) { - result += "\\x{" + pattern.substr(position + 2, 4) + '}'; + if constexpr (!CheckECMA) { + result += "\\x{" + pattern.substr(position + 2, 4) + '}'; + } position += 5; continue; } } + // Named backreference \k (ECMA-262 since 2018) + if (next == 'k' && position + 2 < pattern.size() && + pattern[position + 2] == '<') { + if constexpr (!CheckECMA) { + result += "\\k<"; + } + const auto name_start = position + 3; + position = name_start; + while (position < pattern.size() && pattern[position] != '>') { + if constexpr (!CheckECMA) { + result += pattern[position]; + } + ++position; + } + // Reject unterminated \k + if (position >= pattern.size() || position == name_start) { + if constexpr (CheckECMA) { + return false; + } else { + return std::nullopt; + } + } + if constexpr (!CheckECMA) { + result += '>'; + } + continue; + } + if ((next == 'p' || next == 'P') && position + 2 < pattern.size() && pattern[position + 2] == '{') { const auto start = position; @@ -742,13 +848,19 @@ inline auto preprocess_regex(const std::string &pattern) if (position < pattern.size()) { if (auto translated = translate_property(name, next == 'P')) { - result += *translated; + if constexpr (!CheckECMA) { + result += *translated; + } } else { - result += pattern.substr(start, position - start + 1); + if constexpr (!CheckECMA) { + result += pattern.substr(start, position - start + 1); + } } } else { position = start; - result += current; + if constexpr (!CheckECMA) { + result += current; + } } continue; @@ -756,18 +868,42 @@ inline auto preprocess_regex(const std::string &pattern) if (const auto *expansion = find_shorthand(next)) { if (in_class && expansion->inside_class.empty()) { - result += std::string{current} + next; + if constexpr (!CheckECMA) { + result += std::string{current} + next; + } } else { - result += in_class ? expansion->inside_class : expansion->outside_class; + if constexpr (!CheckECMA) { + result += + in_class ? expansion->inside_class : expansion->outside_class; + } } ++position; } else { - result += current; + // Reject escape sequences that are not valid in ECMA-262 strict mode + constexpr std::string_view ecma_remaining_escapes{"tnrfvcx0"}; + const bool is_ecma_escape{ecma_remaining_escapes.contains(next) || + v_flag_syntax.contains(next) || + (next >= '1' && next <= '9')}; + if (!is_ecma_escape) { + if constexpr (CheckECMA) { + return false; + } else { + return std::nullopt; + } + } + + if constexpr (!CheckECMA) { + result += current; + } } } - return result; + if constexpr (CheckECMA) { + return true; + } else { + return result; + } } } // namespace sourcemeta::core diff --git a/src/core/regex/regex.cc b/src/core/regex/regex.cc index 094857bcd..f3b4e0146 100644 --- a/src/core/regex/regex.cc +++ b/src/core/regex/regex.cc @@ -59,7 +59,7 @@ auto to_regex(const std::string_view pattern) -> std::optional { return RegexTypeRange{minimum, maximum}; } - const auto pcre2_pattern{preprocess_regex(std::string{pattern})}; + const auto pcre2_pattern{preprocess_regex(std::string{pattern})}; if (!pcre2_pattern.has_value()) { return std::nullopt; } @@ -115,4 +115,27 @@ auto matches_if_valid(const std::string_view pattern, return regex.has_value() && matches(regex.value(), value); } +auto is_regex_ecma(const std::string_view pattern) -> bool { + const auto pcre2_pattern{preprocess_regex(std::string{pattern})}; + if (!pcre2_pattern.has_value()) { + return false; + } + + int pcre2_error_code{0}; + PCRE2_SIZE pcre2_error_offset{0}; + pcre2_code *pcre2_regex_raw{pcre2_compile( + reinterpret_cast(pcre2_pattern.value().c_str()), + pcre2_pattern.value().size(), + PCRE2_UTF | PCRE2_UCP | PCRE2_NO_AUTO_CAPTURE | PCRE2_DOTALL | + PCRE2_DOLLAR_ENDONLY | PCRE2_NEVER_BACKSLASH_C | PCRE2_NO_UTF_CHECK, + &pcre2_error_code, &pcre2_error_offset, nullptr)}; + + if (pcre2_regex_raw == nullptr) { + return false; + } + + pcre2_code_free(pcre2_regex_raw); + return true; +} + } // namespace sourcemeta::core diff --git a/test/regex/CMakeLists.txt b/test/regex/CMakeLists.txt index 388b79043..608d44402 100644 --- a/test/regex/CMakeLists.txt +++ b/test/regex/CMakeLists.txt @@ -3,6 +3,7 @@ sourcemeta_googletest(NAMESPACE sourcemeta PROJECT core NAME regex regex_matches_if_valid_test.cc regex_matches_ecma262_test.cc regex_matches_rfc9485_test.cc + regex_is_ecma_test.cc regex_to_regex_test.cc regex_test.cc) diff --git a/test/regex/regex_is_ecma_test.cc b/test/regex/regex_is_ecma_test.cc new file mode 100644 index 000000000..c8a05a419 --- /dev/null +++ b/test/regex/regex_is_ecma_test.cc @@ -0,0 +1,305 @@ +#include + +#include + +TEST(Regex_is_ecma, suite_valid_basic) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("([abc])+\\s+$")); +} + +TEST(Regex_is_ecma, suite_invalid_unclosed_paren) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("^(abc]")); +} + +TEST(Regex_is_ecma, suite_invalid_perl_extension_alarm) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("\\a")); +} + +TEST(Regex_is_ecma, valid_empty) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("")); +} + +TEST(Regex_is_ecma, valid_anchor_start) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("^foo")); +} + +TEST(Regex_is_ecma, valid_anchor_end) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("foo$")); +} + +TEST(Regex_is_ecma, valid_anchor_both) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("^foo$")); +} + +TEST(Regex_is_ecma, valid_character_class) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[abc]")); +} + +TEST(Regex_is_ecma, valid_negated_class) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[^abc]")); +} + +TEST(Regex_is_ecma, valid_range_class) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[a-z]")); +} + +TEST(Regex_is_ecma, invalid_unclosed_class) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("[abc")); +} + +TEST(Regex_is_ecma, valid_digit_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\d")); +} + +TEST(Regex_is_ecma, valid_word_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\w")); +} + +TEST(Regex_is_ecma, valid_space_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\s")); +} + +TEST(Regex_is_ecma, valid_word_boundary) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\bfoo\\b")); +} + +TEST(Regex_is_ecma, valid_newline_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\n")); +} + +TEST(Regex_is_ecma, valid_tab_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\t")); +} + +TEST(Regex_is_ecma, valid_carriage_return_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\r")); +} + +TEST(Regex_is_ecma, valid_form_feed_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\f")); +} + +TEST(Regex_is_ecma, valid_vertical_tab_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\v")); +} + +TEST(Regex_is_ecma, valid_null_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\0")); +} + +TEST(Regex_is_ecma, valid_hex_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\x41")); +} + +TEST(Regex_is_ecma, valid_unicode_4digit) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\u0041")); +} + +TEST(Regex_is_ecma, valid_unicode_braced) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\u{1F600}")); +} + +TEST(Regex_is_ecma, valid_control_escape) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\cA")); +} + +TEST(Regex_is_ecma, valid_unicode_property) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Letter}")); +} + +TEST(Regex_is_ecma, invalid_alarm_escape) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("\\a")); +} + +TEST(Regex_is_ecma, invalid_escape_e) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("\\e")); +} + +TEST(Regex_is_ecma, invalid_escape_h) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("\\h")); +} + +TEST(Regex_is_ecma, invalid_escape_q) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("\\q")); +} + +TEST(Regex_is_ecma, valid_quantifier_star) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a*")); +} + +TEST(Regex_is_ecma, valid_quantifier_plus) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a+")); +} + +TEST(Regex_is_ecma, valid_quantifier_optional) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a?")); +} + +TEST(Regex_is_ecma, valid_quantifier_range) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{2,5}")); +} + +TEST(Regex_is_ecma, valid_quantifier_exact) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{3}")); +} + +TEST(Regex_is_ecma, valid_quantifier_open) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{3,}")); +} + +TEST(Regex_is_ecma, invalid_quantifier_reversed) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("a{5,2}")); +} + +TEST(Regex_is_ecma, invalid_quantifier_no_target) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("+")); +} + +TEST(Regex_is_ecma, valid_group) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(foo)")); +} + +TEST(Regex_is_ecma, valid_non_capturing_group) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(?:foo)")); +} + +TEST(Regex_is_ecma, valid_alternation) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("foo|bar")); +} + +TEST(Regex_is_ecma, invalid_unclosed_group) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(foo")); +} + +TEST(Regex_is_ecma, invalid_unopened_group) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("foo)")); +} + +TEST(Regex_is_ecma, valid_lookahead) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("foo(?=bar)")); +} + +TEST(Regex_is_ecma, valid_negative_lookahead) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("foo(?!bar)")); +} + +TEST(Regex_is_ecma, valid_lookbehind) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(?<=foo)bar")); +} + +TEST(Regex_is_ecma, valid_negative_lookbehind) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(?foo)")); +} + +TEST(Regex_is_ecma, valid_named_backreference) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(?foo)\\k")); +} + +TEST(Regex_is_ecma, invalid_python_named_group) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(?Pfoo)")); +} + +TEST(Regex_is_ecma, invalid_atomic_group) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(?>foo)")); +} + +TEST(Regex_is_ecma, invalid_inline_option_group) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(?i)foo")); +} + +TEST(Regex_is_ecma, invalid_inline_option_scoped) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(?i:foo)")); +} + +TEST(Regex_is_ecma, invalid_branch_reset_group) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(?|a|b)")); +} + +TEST(Regex_is_ecma, invalid_conditional_group) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(?(1)yes|no)")); +} + +TEST(Regex_is_ecma, invalid_subroutine_call) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(?&name)")); +} + +TEST(Regex_is_ecma, invalid_recursion) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(?R)")); +} + +TEST(Regex_is_ecma, invalid_backreference_uppercase_k) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("foo\\Kbar")); +} + +TEST(Regex_is_ecma, invalid_line_break_escape) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("\\R")); +} + +TEST(Regex_is_ecma, invalid_quote_sequence) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("\\Qfoo\\E")); +} + +TEST(Regex_is_ecma, invalid_posix_class_alpha) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("[[:alpha:]]")); +} + +TEST(Regex_is_ecma, invalid_possessive_quantifier) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("a*+")); +} + +TEST(Regex_is_ecma, invalid_backtracking_control) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(*FAIL)")); +} + +TEST(Regex_is_ecma, invalid_perl_g_backreference) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("(foo)\\g{1}")); +} + +TEST(Regex_is_ecma, valid_literal_open_bracket_colon_in_class) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[:abc]")); +} + +TEST(Regex_is_ecma, valid_literal_colon_inside_class) { + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[a:b]")); +} + +TEST(Regex_is_ecma, invalid_unterminated_named_backreference) { + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("\\k")); +} diff --git a/test/regex/regex_matches_ecma262_test.cc b/test/regex/regex_matches_ecma262_test.cc index c16d62aa0..c5c3bd65f 100644 --- a/test/regex/regex_matches_ecma262_test.cc +++ b/test/regex/regex_matches_ecma262_test.cc @@ -7,6 +7,7 @@ TEST(Regex_matches, ecma262_anchor_start) { const auto regex{sourcemeta::core::to_regex("^foo")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("^foo")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foobar")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "barfoo")); @@ -15,6 +16,7 @@ TEST(Regex_matches, ecma262_anchor_start) { TEST(Regex_matches, ecma262_anchor_end) { const auto regex{sourcemeta::core::to_regex("foo$")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("foo$")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "barfoo")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "foobar")); @@ -23,6 +25,7 @@ TEST(Regex_matches, ecma262_anchor_end) { TEST(Regex_matches, ecma262_anchor_both) { const auto regex{sourcemeta::core::to_regex("^foo$")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("^foo$")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "foobar")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "barfoo")); @@ -31,6 +34,7 @@ TEST(Regex_matches, ecma262_anchor_both) { TEST(Regex_matches, ecma262_anchor_start_with_alternation) { const auto regex{sourcemeta::core::to_regex("^(foo|bar)")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("^(foo|bar)")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "bar")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "baz")); @@ -39,6 +43,7 @@ TEST(Regex_matches, ecma262_anchor_start_with_alternation) { TEST(Regex_matches, ecma262_digit_escape) { const auto regex{sourcemeta::core::to_regex("\\d+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\d+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "123")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "0")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "9")); @@ -48,6 +53,7 @@ TEST(Regex_matches, ecma262_digit_escape) { TEST(Regex_matches, ecma262_non_digit_escape) { const auto regex{sourcemeta::core::to_regex("\\D+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\D+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "123")); @@ -56,6 +62,7 @@ TEST(Regex_matches, ecma262_non_digit_escape) { TEST(Regex_matches, ecma262_word_escape) { const auto regex{sourcemeta::core::to_regex("\\w+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\w+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ABC")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "123")); @@ -66,6 +73,7 @@ TEST(Regex_matches, ecma262_word_escape) { TEST(Regex_matches, ecma262_non_word_escape) { const auto regex{sourcemeta::core::to_regex("\\W+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\W+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "!!!")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), " ")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "abc")); @@ -74,6 +82,7 @@ TEST(Regex_matches, ecma262_non_word_escape) { TEST(Regex_matches, ecma262_whitespace_escape) { const auto regex{sourcemeta::core::to_regex("\\s+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\s+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), " ")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\t")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\n")); @@ -84,6 +93,7 @@ TEST(Regex_matches, ecma262_whitespace_escape) { TEST(Regex_matches, ecma262_non_whitespace_escape) { const auto regex{sourcemeta::core::to_regex("\\S+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\S+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "123")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), " ")); @@ -92,6 +102,7 @@ TEST(Regex_matches, ecma262_non_whitespace_escape) { TEST(Regex_matches, ecma262_word_boundary_start) { const auto regex{sourcemeta::core::to_regex("\\bfoo")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\bfoo")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo bar")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), " foo")); @@ -101,6 +112,7 @@ TEST(Regex_matches, ecma262_word_boundary_start) { TEST(Regex_matches, ecma262_word_boundary_end) { const auto regex{sourcemeta::core::to_regex("foo\\b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("foo\\b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo ")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "bar foo")); @@ -110,6 +122,7 @@ TEST(Regex_matches, ecma262_word_boundary_end) { TEST(Regex_matches, ecma262_word_boundary_both) { const auto regex{sourcemeta::core::to_regex("\\bfoo\\b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\bfoo\\b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo bar")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "bar foo baz")); @@ -119,6 +132,7 @@ TEST(Regex_matches, ecma262_word_boundary_both) { TEST(Regex_matches, ecma262_non_word_boundary) { const auto regex{sourcemeta::core::to_regex("\\Boo")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\Boo")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foo")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "oo")); } @@ -126,6 +140,7 @@ TEST(Regex_matches, ecma262_non_word_boundary) { TEST(Regex_matches, ecma262_hex_escape_2digit) { const auto regex{sourcemeta::core::to_regex("\\x41")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\x41")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "A")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "B")); } @@ -133,6 +148,7 @@ TEST(Regex_matches, ecma262_hex_escape_2digit) { TEST(Regex_matches, ecma262_hex_escape_in_pattern) { const auto regex{sourcemeta::core::to_regex("a\\x20b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\x20b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a b")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ab")); } @@ -140,6 +156,7 @@ TEST(Regex_matches, ecma262_hex_escape_in_pattern) { TEST(Regex_matches, ecma262_unicode_escape_4digit) { const auto regex{sourcemeta::core::to_regex("\\u0041")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\u0041")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "A")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "B")); } @@ -147,6 +164,7 @@ TEST(Regex_matches, ecma262_unicode_escape_4digit) { TEST(Regex_matches, ecma262_unicode_escape_brace) { const auto regex{sourcemeta::core::to_regex("\\u{1F600}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\u{1F600}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "😀")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "A")); } @@ -154,6 +172,7 @@ TEST(Regex_matches, ecma262_unicode_escape_brace) { TEST(Regex_matches, ecma262_null_escape) { const auto regex{sourcemeta::core::to_regex("a\\0b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\0b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), std::string("a\0b", 3))); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ab")); } @@ -161,6 +180,7 @@ TEST(Regex_matches, ecma262_null_escape) { TEST(Regex_matches, ecma262_non_capturing_group) { const auto regex{sourcemeta::core::to_regex("(?:abc)+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(?:abc)+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abcabc")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ab")); @@ -169,6 +189,7 @@ TEST(Regex_matches, ecma262_non_capturing_group) { TEST(Regex_matches, ecma262_lookahead_positive) { const auto regex{sourcemeta::core::to_regex("foo(?=bar)")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("foo(?=bar)")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foobar")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "foobaz")); } @@ -176,6 +197,7 @@ TEST(Regex_matches, ecma262_lookahead_positive) { TEST(Regex_matches, ecma262_lookahead_negative) { const auto regex{sourcemeta::core::to_regex("foo(?!bar)")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("foo(?!bar)")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foobaz")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "foobar")); } @@ -183,6 +205,7 @@ TEST(Regex_matches, ecma262_lookahead_negative) { TEST(Regex_matches, ecma262_lookbehind_positive) { const auto regex{sourcemeta::core::to_regex("(?<=foo)bar")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(?<=foo)bar")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foobar")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "bazbar")); } @@ -190,6 +213,7 @@ TEST(Regex_matches, ecma262_lookbehind_positive) { TEST(Regex_matches, ecma262_lookbehind_negative) { const auto regex{sourcemeta::core::to_regex("(?]--[=]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[<=>]--[=]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "<")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), ">")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "=")); @@ -2751,6 +3099,7 @@ TEST(Regex_matches, ecma262_v_flag_equals_and_less_greater) { TEST(Regex_matches, ecma262_v_flag_curly_braces_in_class) { const auto regex{sourcemeta::core::to_regex("[[\\{\\}]--[\\{]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[\\{\\}]--[\\{]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "}")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "{")); } @@ -2758,6 +3107,7 @@ TEST(Regex_matches, ecma262_v_flag_curly_braces_in_class) { TEST(Regex_matches, ecma262_v_flag_parentheses_in_class) { const auto regex{sourcemeta::core::to_regex("[[\\(\\)]--[\\(]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[\\(\\)]--[\\(]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), ")")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "(")); } @@ -2766,6 +3116,8 @@ TEST(Regex_matches, ecma262_v_flag_complex_subtract_intersect_subtract) { const auto regex{ sourcemeta::core::to_regex("[[[[a-z]--[aeiou]]&&[b-y]]--[xyz]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE( + sourcemeta::core::is_regex_ecma("[[[[a-z]--[aeiou]]&&[b-y]]--[xyz]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "w")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); @@ -2776,6 +3128,7 @@ TEST(Regex_matches, ecma262_v_flag_complex_subtract_intersect_subtract) { TEST(Regex_matches, ecma262_v_flag_ampersand_in_class) { const auto regex{sourcemeta::core::to_regex("[[&a]--[a]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[&a]--[a]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "&")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -2783,6 +3136,7 @@ TEST(Regex_matches, ecma262_v_flag_ampersand_in_class) { TEST(Regex_matches, ecma262_v_flag_percent_and_hash) { const auto regex{sourcemeta::core::to_regex("[[%#]--[%]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[%#]--[%]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "#")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "%")); } @@ -2790,6 +3144,7 @@ TEST(Regex_matches, ecma262_v_flag_percent_and_hash) { TEST(Regex_matches, ecma262_v_flag_colon_semicolon_comma) { const auto regex{sourcemeta::core::to_regex("[[:;,]--[;]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[:;,]--[;]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), ":")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), ",")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), ";")); @@ -2798,6 +3153,7 @@ TEST(Regex_matches, ecma262_v_flag_colon_semicolon_comma) { TEST(Regex_matches, ecma262_v_flag_question_exclamation) { const auto regex{sourcemeta::core::to_regex("[[?!]--[?]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[?!]--[?]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "!")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "?")); } @@ -2805,6 +3161,7 @@ TEST(Regex_matches, ecma262_v_flag_question_exclamation) { TEST(Regex_matches, ecma262_v_flag_underscore_intersect) { const auto regex{sourcemeta::core::to_regex("[[\\w]&&[^a-zA-Z0-9]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[\\w]&&[^a-zA-Z0-9]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "_")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "0")); @@ -2813,6 +3170,7 @@ TEST(Regex_matches, ecma262_v_flag_underscore_intersect) { TEST(Regex_matches, ecma262_v_flag_digits_odd_only) { const auto regex{sourcemeta::core::to_regex("[[\\d]--[02468]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[\\d]--[02468]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "1")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "3")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "9")); @@ -2823,6 +3181,7 @@ TEST(Regex_matches, ecma262_v_flag_digits_odd_only) { TEST(Regex_matches, ecma262_v_flag_digits_even_only) { const auto regex{sourcemeta::core::to_regex("[[\\d]&&[02468]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[\\d]&&[02468]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "0")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "4")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "8")); @@ -2833,6 +3192,7 @@ TEST(Regex_matches, ecma262_v_flag_digits_even_only) { TEST(Regex_matches, ecma262_v_flag_single_quote_double_quote) { const auto regex{sourcemeta::core::to_regex("[['\"']--[']]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[['\"']--[']]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\"")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "'")); } @@ -2840,6 +3200,7 @@ TEST(Regex_matches, ecma262_v_flag_single_quote_double_quote) { TEST(Regex_matches, ecma262_v_flag_forward_slash_backslash) { const auto regex{sourcemeta::core::to_regex("[[\\\\]--[\\/]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[\\\\]--[\\/]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\\")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "/")); } @@ -2847,16 +3208,19 @@ TEST(Regex_matches, ecma262_v_flag_forward_slash_backslash) { TEST(Regex_matches, ecma262_v_flag_invalid_unbalanced_parens) { const auto regex{sourcemeta::core::to_regex("([[a-z]--[aeiou]]")}; EXPECT_FALSE(regex.has_value()); + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("([[a-z]--[aeiou]]")); } TEST(Regex_matches, ecma262_v_flag_invalid_bad_quantifier) { const auto regex{sourcemeta::core::to_regex("[[a-z]--[aeiou]]{5,2}")}; EXPECT_FALSE(regex.has_value()); + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("[[a-z]--[aeiou]]{5,2}")); } TEST(Regex_matches, ecma262_v_flag_shorthand_intersection_valid) { const auto regex{sourcemeta::core::to_regex("[\\d&&[0-5]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\d&&[0-5]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "3")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "7")); } @@ -2864,6 +3228,7 @@ TEST(Regex_matches, ecma262_v_flag_shorthand_intersection_valid) { TEST(Regex_matches, ecma262_v_flag_shorthand_subtraction_valid) { const auto regex{sourcemeta::core::to_regex("[\\w--[0-9]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\w--[0-9]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "5")); } @@ -2871,6 +3236,7 @@ TEST(Regex_matches, ecma262_v_flag_shorthand_subtraction_valid) { TEST(Regex_matches, ecma262_v_flag_shorthand_intersection_with_range_valid) { const auto regex{sourcemeta::core::to_regex("[\\w&&[a-z]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\w&&[a-z]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "b")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "B")); } @@ -2878,6 +3244,7 @@ TEST(Regex_matches, ecma262_v_flag_shorthand_intersection_with_range_valid) { TEST(Regex_matches, ecma262_v_flag_shorthand_subtract_single_valid) { const auto regex{sourcemeta::core::to_regex("[\\d--[0]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\d--[0]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "0")); } @@ -2885,6 +3252,7 @@ TEST(Regex_matches, ecma262_v_flag_shorthand_subtract_single_valid) { TEST(Regex_matches, ecma262_v_flag_shorthand_to_shorthand_subtract_valid) { const auto regex{sourcemeta::core::to_regex("[\\w--\\d]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\w--\\d]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "5")); } @@ -2892,6 +3260,7 @@ TEST(Regex_matches, ecma262_v_flag_shorthand_to_shorthand_subtract_valid) { TEST(Regex_matches, ecma262_v_flag_shorthand_to_shorthand_intersect_valid) { const auto regex{sourcemeta::core::to_regex("[\\d&&\\w]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\d&&\\w]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -2899,6 +3268,7 @@ TEST(Regex_matches, ecma262_v_flag_shorthand_to_shorthand_intersect_valid) { TEST(Regex_matches, ecma262_v_flag_chained_shorthand_ops_valid) { const auto regex{sourcemeta::core::to_regex("[\\w--\\d--[_]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\w--\\d--[_]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "5")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "_")); @@ -2907,27 +3277,33 @@ TEST(Regex_matches, ecma262_v_flag_chained_shorthand_ops_valid) { TEST(Regex_matches, ecma262_v_flag_invalid_range_without_nesting) { const auto regex{sourcemeta::core::to_regex("[\\x61-\\x7a--[aeiou]]")}; EXPECT_FALSE(regex.has_value()); + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("[\\x61-\\x7a--[aeiou]]")); } TEST(Regex_matches, ecma262_v_flag_invalid_mixed_ops_without_nesting) { const auto regex{sourcemeta::core::to_regex("[[a-z]--[aeiou]&&[a-m]]")}; EXPECT_FALSE(regex.has_value()); + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("[[a-z]--[aeiou]&&[a-m]]")); } TEST(Regex_matches, ecma262_v_flag_invalid_unescaped_hyphen_in_class) { const auto regex{sourcemeta::core::to_regex("[[a-z-]--[x]]")}; EXPECT_FALSE(regex.has_value()); + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("[[a-z-]--[x]]")); } TEST(Regex_matches, ecma262_v_flag_invalid_unescaped_pipe) { const auto regex{sourcemeta::core::to_regex("[[|a]--[a]]")}; EXPECT_FALSE(regex.has_value()); + EXPECT_FALSE(sourcemeta::core::is_regex_ecma("[[|a]--[a]]")); } TEST(Regex_matches, ecma262_lookahead_with_negated_class) { const auto regex{ sourcemeta::core::to_regex(R"(^(?=[^!*,;{}[\]~\n]+$)(?=(.*\w)).+$)")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma( + R"(^(?=[^!*,;{}[\]~\n]+$)(?=(.*\w)).+$)")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "hello")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "test123")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "!invalid")); @@ -2937,6 +3313,7 @@ TEST(Regex_matches, ecma262_lookahead_with_negated_class) { TEST(Regex_matches, ecma262_literal_open_bracket_in_class) { const auto regex{sourcemeta::core::to_regex("[[(]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[[(]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "[")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "(")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); @@ -2945,6 +3322,7 @@ TEST(Regex_matches, ecma262_literal_open_bracket_in_class) { TEST(Regex_matches, ecma262_literal_close_bracket_in_class) { const auto regex{sourcemeta::core::to_regex(R"([)\]])")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma(R"([)\]])")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), ")")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "]")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); @@ -2953,6 +3331,7 @@ TEST(Regex_matches, ecma262_literal_close_bracket_in_class) { TEST(Regex_matches, ecma262_bracket_classes_in_complex_pattern) { const auto regex{sourcemeta::core::to_regex(R"(^[[(]\d+,\d+[)\]]$)")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma(R"(^[[(]\d+,\d+[)\]]$)")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "[1,2]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "(1,2)")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "[1,2)")); @@ -2964,6 +3343,8 @@ TEST(Regex_matches, ecma262_datetime_range_pattern) { const auto regex{sourcemeta::core::to_regex( R"(^((\d{4}-\d{2}-\d{2})|([[(](((\d{4}-\d{2}-\d{2}([Tt]\d{2}:\d{2}:\d{2}(.\d{1,6})?[Zz])?),(\d{4}-\d{2}-\d{2}([Tt]\d{2}:\d{2}:\d{2}(.\d{1,6})?[Zz])?)?)|(,(\d{4}-\d{2}-\d{2}([Tt]\d{2}:\d{2}:\d{2}(.\d{1,6})?[Zz])?)))[)\]]))$)")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma( + R"(^((\d{4}-\d{2}-\d{2})|([[(](((\d{4}-\d{2}-\d{2}([Tt]\d{2}:\d{2}:\d{2}(.\d{1,6})?[Zz])?),(\d{4}-\d{2}-\d{2}([Tt]\d{2}:\d{2}:\d{2}(.\d{1,6})?[Zz])?)?)|(,(\d{4}-\d{2}-\d{2}([Tt]\d{2}:\d{2}:\d{2}(.\d{1,6})?[Zz])?)))[)\]]))$)")); EXPECT_TRUE( sourcemeta::core::matches(regex.value(), "[2023-04-28T00:00:00Z,]")); EXPECT_TRUE( diff --git a/test/regex/regex_matches_rfc9485_test.cc b/test/regex/regex_matches_rfc9485_test.cc index 418f63b6e..254506d41 100644 --- a/test/regex/regex_matches_rfc9485_test.cc +++ b/test/regex/regex_matches_rfc9485_test.cc @@ -9,6 +9,7 @@ TEST(Regex_matches, rfc9485_edge_dollar_literal) { // middle. We prefer ECMA-262 compliance where $ is ALWAYS an assertion. const auto regex{sourcemeta::core::to_regex("a$b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a$b")); // In ECMA-262, $ is always an end assertion, never a literal // Pattern "a$b" means: match "a", assert end, match "b" // This can NEVER match anything @@ -21,6 +22,7 @@ TEST(Regex_matches, rfc9485_preprocessing_escaped_backslash_dollar) { // middle. We prefer ECMA-262 compliance where $ is ALWAYS an assertion. const auto regex{sourcemeta::core::to_regex("\\\\$foo")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\\\$foo")); // In ECMA-262: \\ = literal backslash, $ = end assertion, foo = literal "foo" // Pattern "\\$foo" means: match backslash, assert end, match "foo" // This can NEVER match anything @@ -31,6 +33,7 @@ TEST(Regex_matches, rfc9485_preprocessing_escaped_backslash_dollar) { TEST(Regex_matches, rfc9485_literal_single_char) { const auto regex{sourcemeta::core::to_regex("a")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "bar")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "xyz")); @@ -39,6 +42,7 @@ TEST(Regex_matches, rfc9485_literal_single_char) { TEST(Regex_matches, rfc9485_literal_sequence) { const auto regex{sourcemeta::core::to_regex("hello")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("hello")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "hello")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "hello world")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "world")); @@ -47,6 +51,7 @@ TEST(Regex_matches, rfc9485_literal_sequence) { TEST(Regex_matches, rfc9485_dot_wildcard) { const auto regex{sourcemeta::core::to_regex("a.c")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a.c")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "axc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a1c")); @@ -56,6 +61,7 @@ TEST(Regex_matches, rfc9485_dot_wildcard) { TEST(Regex_matches, rfc9485_quantifier_star) { const auto regex{sourcemeta::core::to_regex("ab*c")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("ab*c")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ac")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abbc")); @@ -66,6 +72,7 @@ TEST(Regex_matches, rfc9485_quantifier_star) { TEST(Regex_matches, rfc9485_quantifier_plus) { const auto regex{sourcemeta::core::to_regex("ab+c")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("ab+c")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abbc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abbbc")); @@ -75,6 +82,7 @@ TEST(Regex_matches, rfc9485_quantifier_plus) { TEST(Regex_matches, rfc9485_quantifier_question) { const auto regex{sourcemeta::core::to_regex("ab?c")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("ab?c")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ac")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "abbc")); @@ -83,6 +91,7 @@ TEST(Regex_matches, rfc9485_quantifier_question) { TEST(Regex_matches, rfc9485_quantifier_exact) { const auto regex{sourcemeta::core::to_regex("a{3}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{3}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aaa")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aaaa")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "aa")); @@ -91,6 +100,7 @@ TEST(Regex_matches, rfc9485_quantifier_exact) { TEST(Regex_matches, rfc9485_quantifier_at_least) { const auto regex{sourcemeta::core::to_regex("a{2,}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{2,}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aa")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aaa")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aaaa")); @@ -100,6 +110,7 @@ TEST(Regex_matches, rfc9485_quantifier_at_least) { TEST(Regex_matches, rfc9485_quantifier_range) { const auto regex{sourcemeta::core::to_regex("a{2,4}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{2,4}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aa")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aaa")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aaaa")); @@ -110,6 +121,7 @@ TEST(Regex_matches, rfc9485_quantifier_range) { TEST(Regex_matches, rfc9485_alternation_simple) { const auto regex{sourcemeta::core::to_regex("cat|dog")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("cat|dog")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "cat")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "dog")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "bird")); @@ -118,6 +130,7 @@ TEST(Regex_matches, rfc9485_alternation_simple) { TEST(Regex_matches, rfc9485_alternation_multiple) { const auto regex{sourcemeta::core::to_regex("red|green|blue")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("red|green|blue")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "red")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "green")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "blue")); @@ -127,6 +140,7 @@ TEST(Regex_matches, rfc9485_alternation_multiple) { TEST(Regex_matches, rfc9485_alternation_empty_branch) { const auto regex{sourcemeta::core::to_regex("a|")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a|")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "xyz")); @@ -135,6 +149,7 @@ TEST(Regex_matches, rfc9485_alternation_empty_branch) { TEST(Regex_matches, rfc9485_charclass_simple) { const auto regex{sourcemeta::core::to_regex("[abc]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[abc]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "c")); @@ -144,6 +159,7 @@ TEST(Regex_matches, rfc9485_charclass_simple) { TEST(Regex_matches, rfc9485_charclass_range) { const auto regex{sourcemeta::core::to_regex("[a-z]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[a-z]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "m")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "z")); @@ -154,6 +170,7 @@ TEST(Regex_matches, rfc9485_charclass_range) { TEST(Regex_matches, rfc9485_charclass_multiple_ranges) { const auto regex{sourcemeta::core::to_regex("[a-zA-Z0-9]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[a-zA-Z0-9]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "Z")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); @@ -163,6 +180,7 @@ TEST(Regex_matches, rfc9485_charclass_multiple_ranges) { TEST(Regex_matches, rfc9485_charclass_negated) { const auto regex{sourcemeta::core::to_regex("[^abc]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[^abc]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "d")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "x")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "1")); @@ -173,6 +191,7 @@ TEST(Regex_matches, rfc9485_charclass_negated) { TEST(Regex_matches, rfc9485_charclass_dash_at_start) { const auto regex{sourcemeta::core::to_regex("[-abc]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[-abc]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "-")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "x")); @@ -181,6 +200,7 @@ TEST(Regex_matches, rfc9485_charclass_dash_at_start) { TEST(Regex_matches, rfc9485_charclass_dash_at_end) { const auto regex{sourcemeta::core::to_regex("[abc-]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[abc-]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "-")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "x")); @@ -189,6 +209,7 @@ TEST(Regex_matches, rfc9485_charclass_dash_at_end) { TEST(Regex_matches, rfc9485_escape_left_paren) { const auto regex{sourcemeta::core::to_regex("\\(test")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\(test")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "(test")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "test")); } @@ -196,6 +217,7 @@ TEST(Regex_matches, rfc9485_escape_left_paren) { TEST(Regex_matches, rfc9485_escape_right_paren) { const auto regex{sourcemeta::core::to_regex("test\\)")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("test\\)")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "test)")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "test")); } @@ -203,6 +225,7 @@ TEST(Regex_matches, rfc9485_escape_right_paren) { TEST(Regex_matches, rfc9485_escape_left_bracket) { const auto regex{sourcemeta::core::to_regex("\\[test")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\[test")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "[test")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "test")); } @@ -210,6 +233,7 @@ TEST(Regex_matches, rfc9485_escape_left_bracket) { TEST(Regex_matches, rfc9485_escape_right_bracket) { const auto regex{sourcemeta::core::to_regex("test\\]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("test\\]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "test]")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "test")); } @@ -217,6 +241,7 @@ TEST(Regex_matches, rfc9485_escape_right_bracket) { TEST(Regex_matches, rfc9485_escape_left_brace) { const auto regex{sourcemeta::core::to_regex("\\{test")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\{test")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "{test")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "test")); } @@ -224,6 +249,7 @@ TEST(Regex_matches, rfc9485_escape_left_brace) { TEST(Regex_matches, rfc9485_escape_right_brace) { const auto regex{sourcemeta::core::to_regex("test\\}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("test\\}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "test}")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "test")); } @@ -231,6 +257,7 @@ TEST(Regex_matches, rfc9485_escape_right_brace) { TEST(Regex_matches, rfc9485_escape_asterisk) { const auto regex{sourcemeta::core::to_regex("a\\*b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\*b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a*b")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ab")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "aab")); @@ -239,6 +266,7 @@ TEST(Regex_matches, rfc9485_escape_asterisk) { TEST(Regex_matches, rfc9485_escape_plus) { const auto regex{sourcemeta::core::to_regex("a\\+b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\+b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a+b")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ab")); } @@ -246,6 +274,7 @@ TEST(Regex_matches, rfc9485_escape_plus) { TEST(Regex_matches, rfc9485_escape_question) { const auto regex{sourcemeta::core::to_regex("a\\?b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\?b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a?b")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ab")); } @@ -253,6 +282,7 @@ TEST(Regex_matches, rfc9485_escape_question) { TEST(Regex_matches, rfc9485_escape_dot) { const auto regex{sourcemeta::core::to_regex("a\\.b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\.b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a.b")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "axb")); } @@ -260,6 +290,7 @@ TEST(Regex_matches, rfc9485_escape_dot) { TEST(Regex_matches, rfc9485_escape_dash) { const auto regex{sourcemeta::core::to_regex("a\\-b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\-b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a-b")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ab")); } @@ -267,6 +298,7 @@ TEST(Regex_matches, rfc9485_escape_dash) { TEST(Regex_matches, rfc9485_escape_newline) { const auto regex{sourcemeta::core::to_regex("a\\nb")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\nb")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a\nb")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "anb")); } @@ -274,6 +306,7 @@ TEST(Regex_matches, rfc9485_escape_newline) { TEST(Regex_matches, rfc9485_escape_carriage_return) { const auto regex{sourcemeta::core::to_regex("a\\rb")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\rb")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a\rb")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "arb")); } @@ -281,6 +314,7 @@ TEST(Regex_matches, rfc9485_escape_carriage_return) { TEST(Regex_matches, rfc9485_escape_tab) { const auto regex{sourcemeta::core::to_regex("a\\tb")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\tb")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a\tb")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "atb")); } @@ -288,6 +322,7 @@ TEST(Regex_matches, rfc9485_escape_tab) { TEST(Regex_matches, rfc9485_unicode_property_letter) { const auto regex{sourcemeta::core::to_regex("\\p{L}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{L}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "Z")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "é")); @@ -299,6 +334,7 @@ TEST(Regex_matches, rfc9485_unicode_property_letter) { TEST(Regex_matches, rfc9485_unicode_property_uppercase_letter) { const auto regex{sourcemeta::core::to_regex("\\p{Lu}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Lu}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "A")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "Z")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); @@ -308,6 +344,7 @@ TEST(Regex_matches, rfc9485_unicode_property_uppercase_letter) { TEST(Regex_matches, rfc9485_unicode_property_lowercase_letter) { const auto regex{sourcemeta::core::to_regex("\\p{Ll}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Ll}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "z")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "A")); @@ -317,6 +354,7 @@ TEST(Regex_matches, rfc9485_unicode_property_lowercase_letter) { TEST(Regex_matches, rfc9485_unicode_property_titlecase_letter) { const auto regex{sourcemeta::core::to_regex("\\p{Lt}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Lt}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u01C5")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -324,6 +362,7 @@ TEST(Regex_matches, rfc9485_unicode_property_titlecase_letter) { TEST(Regex_matches, rfc9485_unicode_property_modifier_letter) { const auto regex{sourcemeta::core::to_regex("\\p{Lm}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Lm}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u02B0")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -331,6 +370,7 @@ TEST(Regex_matches, rfc9485_unicode_property_modifier_letter) { TEST(Regex_matches, rfc9485_unicode_property_other_letter) { const auto regex{sourcemeta::core::to_regex("\\p{Lo}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Lo}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "中")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -338,6 +378,7 @@ TEST(Regex_matches, rfc9485_unicode_property_other_letter) { TEST(Regex_matches, rfc9485_unicode_property_mark) { const auto regex{sourcemeta::core::to_regex("\\p{M}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{M}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u0300")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -345,6 +386,7 @@ TEST(Regex_matches, rfc9485_unicode_property_mark) { TEST(Regex_matches, rfc9485_unicode_property_nonspacing_mark) { const auto regex{sourcemeta::core::to_regex("\\p{Mn}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Mn}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u0300")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -352,6 +394,7 @@ TEST(Regex_matches, rfc9485_unicode_property_nonspacing_mark) { TEST(Regex_matches, rfc9485_unicode_property_spacing_mark) { const auto regex{sourcemeta::core::to_regex("\\p{Mc}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Mc}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u0903")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -359,6 +402,7 @@ TEST(Regex_matches, rfc9485_unicode_property_spacing_mark) { TEST(Regex_matches, rfc9485_unicode_property_enclosing_mark) { const auto regex{sourcemeta::core::to_regex("\\p{Me}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Me}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u0488")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -366,6 +410,7 @@ TEST(Regex_matches, rfc9485_unicode_property_enclosing_mark) { TEST(Regex_matches, rfc9485_unicode_property_number) { const auto regex{sourcemeta::core::to_regex("\\p{N}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{N}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "0")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u0660")); @@ -375,6 +420,7 @@ TEST(Regex_matches, rfc9485_unicode_property_number) { TEST(Regex_matches, rfc9485_unicode_property_decimal_number) { const auto regex{sourcemeta::core::to_regex("\\p{Nd}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Nd}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "0")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "9")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u0660")); @@ -384,6 +430,7 @@ TEST(Regex_matches, rfc9485_unicode_property_decimal_number) { TEST(Regex_matches, rfc9485_unicode_property_letter_number) { const auto regex{sourcemeta::core::to_regex("\\p{Nl}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Nl}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u2160")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "5")); } @@ -391,6 +438,7 @@ TEST(Regex_matches, rfc9485_unicode_property_letter_number) { TEST(Regex_matches, rfc9485_unicode_property_other_number) { const auto regex{sourcemeta::core::to_regex("\\p{No}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{No}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u00B2")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "5")); } @@ -398,6 +446,7 @@ TEST(Regex_matches, rfc9485_unicode_property_other_number) { TEST(Regex_matches, rfc9485_unicode_property_punctuation) { const auto regex{sourcemeta::core::to_regex("\\p{P}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{P}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "!")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), ".")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), ",")); @@ -407,6 +456,7 @@ TEST(Regex_matches, rfc9485_unicode_property_punctuation) { TEST(Regex_matches, rfc9485_unicode_property_connector_punctuation) { const auto regex{sourcemeta::core::to_regex("\\p{Pc}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Pc}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "_")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), ".")); } @@ -414,6 +464,7 @@ TEST(Regex_matches, rfc9485_unicode_property_connector_punctuation) { TEST(Regex_matches, rfc9485_unicode_property_dash_punctuation) { const auto regex{sourcemeta::core::to_regex("\\p{Pd}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Pd}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "-")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), ".")); } @@ -421,6 +472,7 @@ TEST(Regex_matches, rfc9485_unicode_property_dash_punctuation) { TEST(Regex_matches, rfc9485_unicode_property_open_punctuation) { const auto regex{sourcemeta::core::to_regex("\\p{Ps}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Ps}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "(")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "[")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), ")")); @@ -429,6 +481,7 @@ TEST(Regex_matches, rfc9485_unicode_property_open_punctuation) { TEST(Regex_matches, rfc9485_unicode_property_close_punctuation) { const auto regex{sourcemeta::core::to_regex("\\p{Pe}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Pe}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), ")")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "]")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "(")); @@ -437,6 +490,7 @@ TEST(Regex_matches, rfc9485_unicode_property_close_punctuation) { TEST(Regex_matches, rfc9485_unicode_property_initial_punctuation) { const auto regex{sourcemeta::core::to_regex("\\p{Pi}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Pi}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u00AB")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), ".")); } @@ -444,6 +498,7 @@ TEST(Regex_matches, rfc9485_unicode_property_initial_punctuation) { TEST(Regex_matches, rfc9485_unicode_property_final_punctuation) { const auto regex{sourcemeta::core::to_regex("\\p{Pf}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Pf}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u00BB")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), ".")); } @@ -451,6 +506,7 @@ TEST(Regex_matches, rfc9485_unicode_property_final_punctuation) { TEST(Regex_matches, rfc9485_unicode_property_other_punctuation) { const auto regex{sourcemeta::core::to_regex("\\p{Po}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Po}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "!")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), ".")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "(")); @@ -459,6 +515,7 @@ TEST(Regex_matches, rfc9485_unicode_property_other_punctuation) { TEST(Regex_matches, rfc9485_unicode_property_separator) { const auto regex{sourcemeta::core::to_regex("\\p{Z}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Z}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), " ")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u00A0")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); @@ -467,6 +524,7 @@ TEST(Regex_matches, rfc9485_unicode_property_separator) { TEST(Regex_matches, rfc9485_unicode_property_space_separator) { const auto regex{sourcemeta::core::to_regex("\\p{Zs}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Zs}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), " ")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u00A0")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "\n")); @@ -475,6 +533,7 @@ TEST(Regex_matches, rfc9485_unicode_property_space_separator) { TEST(Regex_matches, rfc9485_unicode_property_line_separator) { const auto regex{sourcemeta::core::to_regex("\\p{Zl}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Zl}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u2028")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), " ")); } @@ -482,6 +541,7 @@ TEST(Regex_matches, rfc9485_unicode_property_line_separator) { TEST(Regex_matches, rfc9485_unicode_property_paragraph_separator) { const auto regex{sourcemeta::core::to_regex("\\p{Zp}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Zp}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u2029")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), " ")); } @@ -489,6 +549,7 @@ TEST(Regex_matches, rfc9485_unicode_property_paragraph_separator) { TEST(Regex_matches, rfc9485_unicode_property_symbol) { const auto regex{sourcemeta::core::to_regex("\\p{S}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{S}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "$")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "©")); @@ -498,6 +559,7 @@ TEST(Regex_matches, rfc9485_unicode_property_symbol) { TEST(Regex_matches, rfc9485_unicode_property_math_symbol) { const auto regex{sourcemeta::core::to_regex("\\p{Sm}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Sm}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "=")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "$")); @@ -506,6 +568,7 @@ TEST(Regex_matches, rfc9485_unicode_property_math_symbol) { TEST(Regex_matches, rfc9485_unicode_property_currency_symbol) { const auto regex{sourcemeta::core::to_regex("\\p{Sc}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Sc}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "$")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "€")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "+")); @@ -514,6 +577,7 @@ TEST(Regex_matches, rfc9485_unicode_property_currency_symbol) { TEST(Regex_matches, rfc9485_unicode_property_modifier_symbol) { const auto regex{sourcemeta::core::to_regex("\\p{Sk}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Sk}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "^")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "$")); } @@ -521,6 +585,7 @@ TEST(Regex_matches, rfc9485_unicode_property_modifier_symbol) { TEST(Regex_matches, rfc9485_unicode_property_other_symbol) { const auto regex{sourcemeta::core::to_regex("\\p{So}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{So}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "©")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "$")); } @@ -528,6 +593,7 @@ TEST(Regex_matches, rfc9485_unicode_property_other_symbol) { TEST(Regex_matches, rfc9485_unicode_property_other) { const auto regex{sourcemeta::core::to_regex("\\p{C}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{C}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), std::string(1, '\0'))); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -535,6 +601,7 @@ TEST(Regex_matches, rfc9485_unicode_property_other) { TEST(Regex_matches, rfc9485_unicode_property_control) { const auto regex{sourcemeta::core::to_regex("\\p{Cc}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Cc}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), std::string(1, '\0'))); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\x1F")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); @@ -543,6 +610,7 @@ TEST(Regex_matches, rfc9485_unicode_property_control) { TEST(Regex_matches, rfc9485_unicode_property_format) { const auto regex{sourcemeta::core::to_regex("\\p{Cf}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Cf}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\u00AD")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -550,11 +618,13 @@ TEST(Regex_matches, rfc9485_unicode_property_format) { TEST(Regex_matches, rfc9485_unicode_property_unassigned) { const auto regex{sourcemeta::core::to_regex("\\p{Cn}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Cn}")); } TEST(Regex_matches, rfc9485_unicode_property_private_use) { const auto regex{sourcemeta::core::to_regex("\\p{Co}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Co}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\uE000")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -562,6 +632,7 @@ TEST(Regex_matches, rfc9485_unicode_property_private_use) { TEST(Regex_matches, rfc9485_unicode_property_complement_letter) { const auto regex{sourcemeta::core::to_regex("\\P{L}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\P{L}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "!")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); @@ -570,6 +641,7 @@ TEST(Regex_matches, rfc9485_unicode_property_complement_letter) { TEST(Regex_matches, rfc9485_unicode_property_complement_number) { const auto regex{sourcemeta::core::to_regex("\\P{N}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\P{N}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "!")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "5")); @@ -578,6 +650,7 @@ TEST(Regex_matches, rfc9485_unicode_property_complement_number) { TEST(Regex_matches, rfc9485_unicode_property_complement_punctuation) { const auto regex{sourcemeta::core::to_regex("\\P{P}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\P{P}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "!")); @@ -586,6 +659,7 @@ TEST(Regex_matches, rfc9485_unicode_property_complement_punctuation) { TEST(Regex_matches, rfc9485_group_simple) { const auto regex{sourcemeta::core::to_regex("(ab)c")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(ab)c")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ac")); } @@ -593,6 +667,7 @@ TEST(Regex_matches, rfc9485_group_simple) { TEST(Regex_matches, rfc9485_group_nested) { const auto regex{sourcemeta::core::to_regex("((ab)c)")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("((ab)c)")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ac")); } @@ -600,6 +675,7 @@ TEST(Regex_matches, rfc9485_group_nested) { TEST(Regex_matches, rfc9485_group_with_quantifier) { const auto regex{sourcemeta::core::to_regex("(ab)+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(ab)+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ab")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abab")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ababab")); @@ -609,6 +685,7 @@ TEST(Regex_matches, rfc9485_group_with_quantifier) { TEST(Regex_matches, rfc9485_group_with_alternation) { const auto regex{sourcemeta::core::to_regex("(cat|dog)s")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(cat|dog)s")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "cats")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "dogs")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "birds")); @@ -617,6 +694,7 @@ TEST(Regex_matches, rfc9485_group_with_alternation) { TEST(Regex_matches, rfc9485_complex_email_like) { const auto regex{sourcemeta::core::to_regex("[a-z]+@[a-z]+\\.[a-z]+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[a-z]+@[a-z]+\\.[a-z]+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "user@example.com")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "test@test.org")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "invalid")); @@ -625,6 +703,7 @@ TEST(Regex_matches, rfc9485_complex_email_like) { TEST(Regex_matches, rfc9485_complex_identifier) { const auto regex{sourcemeta::core::to_regex("[a-zA-Z_][a-zA-Z0-9_]*")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[a-zA-Z_][a-zA-Z0-9_]*")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "variable1")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "_private")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "CONSTANT")); @@ -634,6 +713,7 @@ TEST(Regex_matches, rfc9485_complex_identifier) { TEST(Regex_matches, rfc9485_complex_unicode_word) { const auto regex{sourcemeta::core::to_regex("\\p{L}+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{L}+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "hello")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "世界")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "مرحبا")); @@ -643,6 +723,7 @@ TEST(Regex_matches, rfc9485_complex_unicode_word) { TEST(Regex_matches, rfc9485_complex_mixed_quantifiers) { const auto regex{sourcemeta::core::to_regex("a{2,3}b+c*")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{2,3}b+c*")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aab")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aaab")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aabbb")); @@ -653,6 +734,7 @@ TEST(Regex_matches, rfc9485_complex_mixed_quantifiers) { TEST(Regex_matches, rfc9485_complex_nested_groups_quantifiers) { const auto regex{sourcemeta::core::to_regex("((ab)+c)*")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("((ab)+c)*")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ababc")); @@ -663,6 +745,7 @@ TEST(Regex_matches, rfc9485_complex_nested_groups_quantifiers) { TEST(Regex_matches, rfc9485_edge_empty_pattern) { const auto regex{sourcemeta::core::to_regex("")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "anything")); } @@ -670,6 +753,7 @@ TEST(Regex_matches, rfc9485_edge_empty_pattern) { TEST(Regex_matches, rfc9485_edge_alternation_empty_first) { const auto regex{sourcemeta::core::to_regex("|abc")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("|abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "xyz")); @@ -678,6 +762,7 @@ TEST(Regex_matches, rfc9485_edge_alternation_empty_first) { TEST(Regex_matches, rfc9485_edge_alternation_empty_middle) { const auto regex{sourcemeta::core::to_regex("a||b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a||b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "b")); @@ -687,6 +772,7 @@ TEST(Regex_matches, rfc9485_edge_alternation_empty_middle) { TEST(Regex_matches, rfc9485_edge_alternation_all_empty) { const auto regex{sourcemeta::core::to_regex("||")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("||")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "anything")); } @@ -694,6 +780,7 @@ TEST(Regex_matches, rfc9485_edge_alternation_all_empty) { TEST(Regex_matches, rfc9485_edge_escape_backslash) { const auto regex{sourcemeta::core::to_regex("a\\\\b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\\\b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a\\b")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ab")); } @@ -701,6 +788,7 @@ TEST(Regex_matches, rfc9485_edge_escape_backslash) { TEST(Regex_matches, rfc9485_edge_escape_pipe) { const auto regex{sourcemeta::core::to_regex("a\\|b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\|b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a|b")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "ab")); } @@ -708,12 +796,14 @@ TEST(Regex_matches, rfc9485_edge_escape_pipe) { TEST(Regex_matches, rfc9485_edge_caret_literal) { const auto regex{sourcemeta::core::to_regex("a\\^b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a\\^b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a^b")); } TEST(Regex_matches, rfc9485_edge_quantifier_zero_exact) { const auto regex{sourcemeta::core::to_regex("a{0}b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{0}b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ab")); } @@ -721,6 +811,7 @@ TEST(Regex_matches, rfc9485_edge_quantifier_zero_exact) { TEST(Regex_matches, rfc9485_edge_quantifier_zero_or_more) { const auto regex{sourcemeta::core::to_regex("a{0,}b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{0,}b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ab")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aaab")); @@ -729,6 +820,7 @@ TEST(Regex_matches, rfc9485_edge_quantifier_zero_or_more) { TEST(Regex_matches, rfc9485_edge_quantifier_zero_to_n) { const auto regex{sourcemeta::core::to_regex("a{0,3}b")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{0,3}b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ab")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aab")); @@ -739,6 +831,7 @@ TEST(Regex_matches, rfc9485_edge_quantifier_zero_to_n) { TEST(Regex_matches, rfc9485_edge_nested_groups_deep) { const auto regex{sourcemeta::core::to_regex("(((a)))")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(((a)))")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "b")); } @@ -746,6 +839,7 @@ TEST(Regex_matches, rfc9485_edge_nested_groups_deep) { TEST(Regex_matches, rfc9485_edge_charclass_only_dash) { const auto regex{sourcemeta::core::to_regex("[-]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[-]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "-")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); } @@ -753,6 +847,7 @@ TEST(Regex_matches, rfc9485_edge_charclass_only_dash) { TEST(Regex_matches, rfc9485_edge_charclass_dash_both_ends) { const auto regex{sourcemeta::core::to_regex("[-a-]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[-a-]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "-")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "b")); @@ -761,6 +856,7 @@ TEST(Regex_matches, rfc9485_edge_charclass_dash_both_ends) { TEST(Regex_matches, rfc9485_edge_charclass_mixed_content) { const auto regex{sourcemeta::core::to_regex("[a-z\\p{N}._-]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[a-z\\p{N}._-]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "z")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); @@ -773,6 +869,7 @@ TEST(Regex_matches, rfc9485_edge_charclass_mixed_content) { TEST(Regex_matches, rfc9485_edge_charclass_escaped_bracket) { const auto regex{sourcemeta::core::to_regex("[\\[\\]]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\[\\]]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "[")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "]")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a")); @@ -781,6 +878,7 @@ TEST(Regex_matches, rfc9485_edge_charclass_escaped_bracket) { TEST(Regex_matches, rfc9485_edge_charclass_multiple_ranges) { const auto regex{sourcemeta::core::to_regex("[a-cA-C0-2]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[a-cA-C0-2]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "c")); @@ -798,6 +896,7 @@ TEST(Regex_matches, rfc9485_edge_charclass_multiple_ranges) { TEST(Regex_matches, rfc9485_edge_group_with_alternation_quantified) { const auto regex{sourcemeta::core::to_regex("(a|b){2}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(a|b){2}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aa")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ab")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ba")); @@ -808,6 +907,7 @@ TEST(Regex_matches, rfc9485_edge_group_with_alternation_quantified) { TEST(Regex_matches, rfc9485_edge_multiple_dots) { const auto regex{sourcemeta::core::to_regex("...")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("...")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "123")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a\nb")); @@ -817,6 +917,7 @@ TEST(Regex_matches, rfc9485_edge_multiple_dots) { TEST(Regex_matches, rfc9485_edge_quantifier_large_range) { const auto regex{sourcemeta::core::to_regex("a{100,200}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a{100,200}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), std::string(100, 'a'))); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), std::string(150, 'a'))); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), std::string(200, 'a'))); @@ -826,6 +927,7 @@ TEST(Regex_matches, rfc9485_edge_quantifier_large_range) { TEST(Regex_matches, rfc9485_edge_alternation_with_groups) { const auto regex{sourcemeta::core::to_regex("(abc)|(def)|(ghi)")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(abc)|(def)|(ghi)")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "def")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "ghi")); @@ -835,6 +937,7 @@ TEST(Regex_matches, rfc9485_edge_alternation_with_groups) { TEST(Regex_matches, rfc9485_edge_charclass_with_unicode_properties) { const auto regex{sourcemeta::core::to_regex("[\\p{Lu}\\p{Nd}]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\p{Lu}\\p{Nd}]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "A")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "Z")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); @@ -845,6 +948,8 @@ TEST(Regex_matches, rfc9485_all_major_categories_combined) { const auto regex{sourcemeta::core::to_regex( "[\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{S}\\p{C}]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma( + "[\\p{L}\\p{M}\\p{N}\\p{P}\\p{Z}\\p{S}\\p{C}]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "!")); @@ -855,6 +960,7 @@ TEST(Regex_matches, rfc9485_all_major_categories_combined) { TEST(Regex_matches, rfc9485_complement_all_major_categories) { const auto regex{sourcemeta::core::to_regex("\\P{L}\\P{N}\\P{P}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\P{L}\\P{N}\\P{P}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), " ")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "a ")); } @@ -862,6 +968,7 @@ TEST(Regex_matches, rfc9485_complement_all_major_categories) { TEST(Regex_matches, rfc9485_edge_nested_quantifiers_group) { const auto regex{sourcemeta::core::to_regex("((a+)+)+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("((a+)+)+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aa")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "aaa")); @@ -871,6 +978,7 @@ TEST(Regex_matches, rfc9485_edge_nested_quantifiers_group) { TEST(Regex_matches, rfc9485_edge_charclass_negated_with_range) { const auto regex{sourcemeta::core::to_regex("[^a-z]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[^a-z]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "A")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "!")); @@ -881,6 +989,7 @@ TEST(Regex_matches, rfc9485_edge_charclass_negated_with_range) { TEST(Regex_matches, rfc9485_edge_consecutive_alternations) { const auto regex{sourcemeta::core::to_regex("a|b|c|d|e")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a|b|c|d|e")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "b")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "c")); @@ -892,6 +1001,7 @@ TEST(Regex_matches, rfc9485_edge_consecutive_alternations) { TEST(Regex_matches, rfc9485_edge_group_quantifier_zero_or_one) { const auto regex{sourcemeta::core::to_regex("(abc)?")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("(abc)?")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abc")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "xyz")); @@ -900,6 +1010,7 @@ TEST(Regex_matches, rfc9485_edge_group_quantifier_zero_or_one) { TEST(Regex_matches, rfc9485_edge_mixed_quantifiers_sequence) { const auto regex{sourcemeta::core::to_regex("a?b+c*d{2}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("a?b+c*d{2}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "bdd")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abdd")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "abbcdd")); @@ -910,6 +1021,7 @@ TEST(Regex_matches, rfc9485_edge_mixed_quantifiers_sequence) { TEST(Regex_matches, rfc9485_edge_unicode_in_alternation) { const auto regex{sourcemeta::core::to_regex("\\p{Lu}|\\p{Ll}|\\p{Nd}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\p{Lu}|\\p{Ll}|\\p{Nd}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "A")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "5")); @@ -919,6 +1031,7 @@ TEST(Regex_matches, rfc9485_edge_unicode_in_alternation) { TEST(Regex_matches, rfc9485_edge_charclass_single_char) { const auto regex{sourcemeta::core::to_regex("[a]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[a]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "a")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "b")); } @@ -927,6 +1040,8 @@ TEST(Regex_matches, rfc9485_edge_complex_real_world_email_subset) { const auto regex{sourcemeta::core::to_regex( "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-z]{2,}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma( + "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-z]{2,}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "test@example.com")); EXPECT_TRUE( sourcemeta::core::matches(regex.value(), "user.name+tag@example.co.uk")); @@ -937,6 +1052,7 @@ TEST(Regex_matches, rfc9485_edge_complex_real_world_email_subset) { TEST(Regex_matches, rfc9485_edge_complex_real_world_hex_color) { const auto regex{sourcemeta::core::to_regex("#[0-9a-fA-F]{6}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("#[0-9a-fA-F]{6}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "#FF5733")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "#000000")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "#ffffff")); @@ -947,6 +1063,8 @@ TEST(Regex_matches, rfc9485_edge_complex_real_world_uuid_partial) { const auto regex{sourcemeta::core::to_regex( "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma( + "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}")); EXPECT_TRUE(sourcemeta::core::matches( regex.value(), "550e8400-e29b-41d4-a716-446655440000")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "invalid-uuid")); @@ -955,6 +1073,7 @@ TEST(Regex_matches, rfc9485_edge_complex_real_world_uuid_partial) { TEST(Regex_matches, rfc9485_preprocessing_literal_backslash_p) { const auto regex{sourcemeta::core::to_regex("\\\\p\\{L\\}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\\\p\\{L\\}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\\p{L}")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "A")); } @@ -962,6 +1081,7 @@ TEST(Regex_matches, rfc9485_preprocessing_literal_backslash_p) { TEST(Regex_matches, rfc9485_preprocessing_literal_backslash_P) { const auto regex{sourcemeta::core::to_regex("\\\\P\\{N\\}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\\\P\\{N\\}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\\P{N}")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "5")); } @@ -969,6 +1089,7 @@ TEST(Regex_matches, rfc9485_preprocessing_literal_backslash_P) { TEST(Regex_matches, rfc9485_preprocessing_mixed_escaped_and_unicode) { const auto regex{sourcemeta::core::to_regex("\\\\p\\{L\\} \\p{L}")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("\\\\p\\{L\\} \\p{L}")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\\p{L} A")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "A A")); } @@ -976,6 +1097,7 @@ TEST(Regex_matches, rfc9485_preprocessing_mixed_escaped_and_unicode) { TEST(Regex_matches, rfc9485_quantifier_star_any_string) { const auto regex{sourcemeta::core::to_regex(".*")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma(".*")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foobar")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "")); } @@ -983,6 +1105,7 @@ TEST(Regex_matches, rfc9485_quantifier_star_any_string) { TEST(Regex_matches, rfc9485_quantifier_plus_non_empty) { const auto regex{sourcemeta::core::to_regex(".+")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma(".+")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "foobar")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "")); } @@ -990,18 +1113,21 @@ TEST(Regex_matches, rfc9485_quantifier_plus_non_empty) { TEST(Regex_matches, rfc9485_dot_matches_newline) { const auto regex{sourcemeta::core::to_regex(".")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma(".")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\n")); } TEST(Regex_matches, rfc9485_dot_matches_carriage_return) { const auto regex{sourcemeta::core::to_regex(".")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma(".")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\r")); } TEST(Regex_matches, rfc9485_unicode_range_4byte_deseret) { const auto regex{sourcemeta::core::to_regex("[\\u{10400}-\\u{1044F}]")}; EXPECT_TRUE(regex.has_value()); + EXPECT_TRUE(sourcemeta::core::is_regex_ecma("[\\u{10400}-\\u{1044F}]")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\U00010400")); EXPECT_TRUE(sourcemeta::core::matches(regex.value(), "\U0001044F")); EXPECT_FALSE(sourcemeta::core::matches(regex.value(), "A"));