/* * Copyright (c) 2026-present, the Ladybird developers. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include static regex::ECMAScriptRegex compile_regex(StringView pattern, regex::ECMAScriptCompileFlags flags = {}) { return MUST(regex::ECMAScriptRegex::compile(pattern, flags)); } static bool compile_succeeds(StringView pattern, regex::ECMAScriptCompileFlags flags = {}) { return !regex::ECMAScriptRegex::compile(pattern, flags).is_error(); } static bool matches(StringView pattern, StringView subject, regex::ECMAScriptCompileFlags flags = {}) { auto regex = compile_regex(pattern, flags); auto utf16_subject = Utf16String::from_utf8(subject); auto result = regex.test(utf16_subject, 0); EXPECT(result != regex::MatchResult::LimitExceeded); return result == regex::MatchResult::Match; } static Optional capture_group(regex::ECMAScriptRegex const& regex, Utf16View input, unsigned group_index) { auto start = regex.capture_slot(group_index * 2); auto end = regex.capture_slot(group_index * 2 + 1); if (start < 0 || end < 0) return {}; return input.substring_view(start, end - start); } static void expect_capture_eq(regex::ECMAScriptRegex const& regex, Utf16View input, unsigned group_index, StringView expected) { auto capture = capture_group(regex, input, group_index); EXPECT(capture.has_value()); if (capture.has_value()) EXPECT(*capture == expected); } static void expect_capture_unmatched(regex::ECMAScriptRegex const& regex, unsigned group_index) { EXPECT_EQ(regex.capture_slot(group_index * 2), -1); EXPECT_EQ(regex.capture_slot(group_index * 2 + 1), -1); } TEST_CASE(compile_rejects_invalid_pattern) { auto regex = regex::ECMAScriptRegex::compile("("sv, {}); EXPECT(regex.is_error()); } TEST_CASE(exec_tracks_named_capture_slots) { auto regex = MUST(regex::ECMAScriptRegex::compile("(?foo)(bar)"sv, {})); EXPECT_EQ(regex.capture_count(), 2u); EXPECT_EQ(regex.total_groups(), 3u); EXPECT_EQ(regex.named_groups().size(), 1u); EXPECT_EQ(regex.named_groups()[0].name, "word"sv); EXPECT_EQ(regex.named_groups()[0].index, 1u); EXPECT_EQ(regex.exec(u"foobar"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.capture_slot(0), 0); EXPECT_EQ(regex.capture_slot(1), 6); EXPECT_EQ(regex.capture_slot(2), 0); EXPECT_EQ(regex.capture_slot(3), 3); EXPECT_EQ(regex.capture_slot(4), 3); EXPECT_EQ(regex.capture_slot(5), 6); } TEST_CASE(exec_reports_unmatched_optional_groups) { auto regex = MUST(regex::ECMAScriptRegex::compile("(foo)?bar"sv, {})); EXPECT_EQ(regex.exec(u"bar"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.capture_slot(0), 0); EXPECT_EQ(regex.capture_slot(1), 3); EXPECT_EQ(regex.capture_slot(2), -1); EXPECT_EQ(regex.capture_slot(3), -1); } TEST_CASE(ascii_backed_inputs_preserve_match_results) { auto regex = MUST(regex::ECMAScriptRegex::compile("(?foo)(bar)"sv, {})); EXPECT_EQ(regex.exec("foobar"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.capture_slot(0), 0); EXPECT_EQ(regex.capture_slot(1), 6); EXPECT_EQ(regex.capture_slot(2), 0); EXPECT_EQ(regex.capture_slot(3), 3); EXPECT_EQ(regex.capture_slot(4), 3); EXPECT_EQ(regex.capture_slot(5), 6); EXPECT_EQ(regex.test("foobar"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.find_all("foobar foobar"sv, 0), 2); EXPECT_EQ(regex.find_all_match(0).start, 0); EXPECT_EQ(regex.find_all_match(0).end, 6); EXPECT_EQ(regex.find_all_match(1).start, 7); EXPECT_EQ(regex.find_all_match(1).end, 13); } TEST_CASE(test_honors_ignore_case) { auto regex = MUST(regex::ECMAScriptRegex::compile("casesensitive"sv, { .ignore_case = true })); EXPECT_EQ(regex.test(u"CaseSensitive"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.test(u"something else"sv, 0), regex::MatchResult::NoMatch); } TEST_CASE(ascii_ignore_case_literal_search_preserves_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("zfvr"sv, { .ignore_case = true })); EXPECT_EQ(regex.exec("...ZFVR..."sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.capture_slot(0), 3); EXPECT_EQ(regex.capture_slot(1), 7); EXPECT_EQ(regex.find_all("zfvr ZFVR zFVr"sv, 0), 3); EXPECT_EQ(regex.find_all_match(0).start, 0); EXPECT_EQ(regex.find_all_match(1).start, 5); EXPECT_EQ(regex.find_all_match(2).start, 10); } TEST_CASE(ascii_ignore_case_literal_search_handles_punctuation_prefixes) { auto regex = MUST(regex::ECMAScriptRegex::compile("##yv22##"sv, { .ignore_case = true })); EXPECT_EQ(regex.find_all("##YV22## and ##yv22##"sv, 0), 2); EXPECT_EQ(regex.find_all_match(0).start, 0); EXPECT_EQ(regex.find_all_match(0).end, 8); EXPECT_EQ(regex.find_all_match(1).start, 13); EXPECT_EQ(regex.find_all_match(1).end, 21); } TEST_CASE(ascii_ignore_case_literal_alternation_preserves_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("##yv22##|zfvr|puebzr"sv, { .ignore_case = true })); EXPECT_EQ(regex.find_all("##YV22## zFVr PUEBZR"sv, 0), 3); EXPECT_EQ(regex.find_all_match(0).start, 0); EXPECT_EQ(regex.find_all_match(0).end, 8); EXPECT_EQ(regex.find_all_match(1).start, 9); EXPECT_EQ(regex.find_all_match(1).end, 13); EXPECT_EQ(regex.find_all_match(2).start, 14); EXPECT_EQ(regex.find_all_match(2).end, 20); } TEST_CASE(ascii_ignore_case_literal_alternation_respects_source_order) { auto regex = MUST(regex::ECMAScriptRegex::compile("foo|f"sv, { .ignore_case = true })); EXPECT_EQ(regex.exec("FoO"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.capture_slot(0), 0); EXPECT_EQ(regex.capture_slot(1), 3); } TEST_CASE(unicode_ignore_case_literal_alternation_preserves_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("s|k"sv, { .ignore_case = true, .unicode = true })); EXPECT_EQ(regex.test(u"\u017F"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.test(u"\u212A"sv, 0), regex::MatchResult::Match); } TEST_CASE(word_boundary_literal_preserves_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("\\bfoo\\b"sv, {})); EXPECT_EQ(regex.find_all("foo foo-bar barfoo foo2 _foo foo_"sv, 0), 2); EXPECT_EQ(regex.find_all_match(0).start, 0); EXPECT_EQ(regex.find_all_match(0).end, 3); EXPECT_EQ(regex.find_all_match(1).start, 4); EXPECT_EQ(regex.find_all_match(1).end, 7); } TEST_CASE(ascii_ignore_case_word_boundary_literal_preserves_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("\\bzfvr\\b"sv, { .ignore_case = true })); EXPECT_EQ(regex.find_all("ZFVR zfvr1 _ZFVR zFVr"sv, 0), 2); EXPECT_EQ(regex.find_all_match(0).start, 0); EXPECT_EQ(regex.find_all_match(0).end, 4); EXPECT_EQ(regex.find_all_match(1).start, 17); EXPECT_EQ(regex.find_all_match(1).end, 21); } TEST_CASE(unicode_ignore_case_word_boundary_literal_preserves_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("\\bk\\b"sv, { .ignore_case = true, .unicode = true })); EXPECT_EQ(regex.test(u"\u212A"sv, 0), regex::MatchResult::Match); } TEST_CASE(mixed_positive_class_with_word_builtin_preserves_legacy_ignore_case_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("[\\w\\$]+"sv, { .ignore_case = true })); EXPECT_EQ(regex.test("AZ_09$"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.test(u"\u017F"sv, 0), regex::MatchResult::NoMatch); EXPECT_EQ(regex.test(u"\u212A"sv, 0), regex::MatchResult::NoMatch); } TEST_CASE(mixed_positive_class_with_digit_builtin_preserves_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("[A-Z\\d-]+"sv, { .ignore_case = true })); EXPECT_EQ(regex.test("ABC-123"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.test("abc"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.test("!"sv, 0), regex::MatchResult::NoMatch); } TEST_CASE(find_all_returns_non_overlapping_matches) { auto regex = MUST(regex::ECMAScriptRegex::compile("aba"sv, {})); EXPECT_EQ(regex.find_all(u"aba aba"sv, 0), 2); EXPECT_EQ(regex.find_all_match(0).start, 0); EXPECT_EQ(regex.find_all_match(0).end, 3); EXPECT_EQ(regex.find_all_match(1).start, 4); EXPECT_EQ(regex.find_all_match(1).end, 7); } TEST_CASE(unicode_property_matching_works) { auto regex = MUST(regex::ECMAScriptRegex::compile("\\p{ASCII}+"sv, { .unicode = true })); EXPECT_EQ(regex.test(u"ASCII"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.test(u"πŸ˜€"sv, 0), regex::MatchResult::NoMatch); } TEST_CASE(end_anchored_suffix_patterns_preserve_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("(.*)\\/client-(.*)\\.js$"sv, {})); EXPECT_EQ(regex.test(u"https://cdn.example.com/assets/client-main.js"sv, 0), regex::MatchResult::Match); EXPECT_EQ(regex.test(u""sv, 0), regex::MatchResult::NoMatch); } TEST_CASE(leading_start_or_separator_prefix_preserves_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("(?:^|;)\\s*foo=([^;]*)"sv, {})); { auto subject = Utf16String::from_utf8("foo=bar"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 1, "bar"sv); } { auto subject = Utf16String::from_utf8("a=1; foo=bar; baz=qux"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 1, "bar"sv); } EXPECT_EQ(regex.test(u"a=1; baz=qux"sv, 0), regex::MatchResult::NoMatch); } TEST_CASE(required_literal_prefilter_preserves_assignment_extractors) { auto regex = MUST(regex::ECMAScriptRegex::compile("(?:^|;)\\s*foo=([^;]*)"sv, {})); { auto subject = Utf16String::from_utf8("a=1; bar=baz; foo=qux"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 1, "qux"sv); } EXPECT_EQ(regex.test(u"a=1; bar=baz; quux=7"sv, 0), regex::MatchResult::NoMatch); } TEST_CASE(ascii_ignore_case_required_literal_prefilter_preserves_behavior) { auto regex = MUST(regex::ECMAScriptRegex::compile("\\bfoo\\s*=\\s*([^;]*)"sv, { .ignore_case = true })); { auto subject = Utf16String::from_utf8("FOO = Bar"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 1, "Bar"sv); } EXPECT_EQ(regex.test(u"bar = baz"sv, 0), regex::MatchResult::NoMatch); } TEST_CASE(required_literal_prefilter_handles_common_substrings_across_alternatives) { auto regex = MUST(regex::ECMAScriptRegex::compile("(\\$\\{name\\})|(\\$name\\b)"sv, {})); EXPECT_EQ(regex.find_all("${name} $name"sv, 0), 2); EXPECT_EQ(regex.find_all_match(0).start, 0); EXPECT_EQ(regex.find_all_match(0).end, 7); EXPECT_EQ(regex.find_all_match(1).start, 8); EXPECT_EQ(regex.find_all_match(1).end, 13); EXPECT_EQ(regex.test(u"${other} $other"sv, 0), regex::MatchResult::NoMatch); } TEST_CASE(required_literal_prefilter_compiles_large_exact_quantifiers) { StringBuilder pattern_builder; pattern_builder.append("(?:ab){"sv); pattern_builder.appendff("{}", 1'000'000); pattern_builder.append("}"sv); auto pattern = MUST(pattern_builder.to_string()); EXPECT(compile_succeeds(pattern)); } TEST_CASE(required_literal_prefilter_compiles_long_literal_alternations) { StringBuilder branch_builder; branch_builder.append_repeated("a"sv, 1'024); auto shared_prefix = MUST(branch_builder.to_string()); StringBuilder pattern_builder; pattern_builder.append(shared_prefix); pattern_builder.append("b|"sv); pattern_builder.append(shared_prefix); pattern_builder.append("c"sv); auto pattern = MUST(pattern_builder.to_string()); auto regex = MUST(regex::ECMAScriptRegex::compile(pattern, {})); StringBuilder subject_builder; subject_builder.append(shared_prefix); subject_builder.append("c"sv); auto matching_subject = MUST(subject_builder.to_string()); subject_builder.trim(1); subject_builder.append("d"sv); auto missing_subject = MUST(subject_builder.to_string()); EXPECT_EQ(regex.test(Utf16String::from_utf8(matching_subject), 0), regex::MatchResult::Match); EXPECT_EQ(regex.test(Utf16String::from_utf8(missing_subject), 0), regex::MatchResult::NoMatch); } TEST_CASE(restored_ecmascript_parse_coverage) { struct Test { StringView pattern; bool should_compile { true }; regex::ECMAScriptCompileFlags flags {}; }; static constexpr Test tests[] { { "^hello.$"sv }, { "\\x"sv }, { "\\x1"sv }, { "\\x1"sv, false, { .unicode = true } }, { "\\x11"sv, true, { .unicode = true } }, { "\\"sv, false }, { "(?"sv, false }, { "\\u1234"sv, true, { .unicode = true } }, { "[\\u1234]"sv, true, { .unicode = true } }, { "\\u1"sv, false, { .unicode = true } }, { "[\\u1]"sv, false, { .unicode = true } }, { "{1}"sv, false }, { "{1,2}"sv, false }, { "\\uxxxx"sv, false, { .unicode = true } }, { "\\u{10ffff}"sv, true, { .unicode = true } }, { "\\u{110000}"sv, false, { .unicode = true } }, { "\\p{ASCII}"sv, true, { .unicode = true } }, { "\\p{}"sv, false, { .unicode = true } }, { "\\p{AsCiI}"sv, false, { .unicode = true } }, { "(?a)(?b)"sv, false }, { "(?:(?a)|(?a)(?b))(?:(?c)|(?d))"sv }, { "(?<1a>a)"sv, false }, { "(?<$$_$$>a)"sv }, { "(?<ΓΏ>a)"sv }, { "(?<𝓑𝓻𝓸𝔀𝓷>a)"sv }, { "(?ii:a)"sv, false }, { "(?-:a)"sv, false }, { "(?i)"sv, false }, { "(?-i)"sv, false }, { "["sv, false }, { "[ -"sv, false }, { "[[x[]]]"sv, true, { .unicode_sets = true } }, { "[\\w--x]"sv, true, { .unicode_sets = true } }, }; for (auto const& test : tests) EXPECT_EQ(compile_succeeds(test.pattern, test.flags), test.should_compile); } TEST_CASE(restored_ecmascript_match_coverage) { struct Test { StringView pattern; StringView subject; bool should_match { true }; regex::ECMAScriptCompileFlags flags {}; }; static constexpr Test tests[] { { "^hello.$"sv, "hello1"sv }, { "^h{0,1}ello.$"sv, "ello1"sv }, { "^hell\\x6f1$"sv, "hello1"sv }, { "^hel(?l.)1$"sv, "hello1"sv }, { "\\b.*\\b"sv, "hello1"sv }, { "bar(?=f.)foo"sv, "barfoo"sv }, { "bar(?=foo)bar"sv, "barbar"sv, false }, { "bar(?!foo)bar"sv, "barbar"sv }, { "bar(?!bar)bar"sv, "barbar"sv, false }, { "bar.*(?<=foo)"sv, "barbar"sv, false }, { "bar.*(?a)|(?b))\\k"sv); auto subject = Utf16String::from_utf8("bb"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 0, "bb"sv); expect_capture_unmatched(regex, 1); expect_capture_eq(regex, subject, 2, "b"sv); } { auto regex = compile_regex("(?:(?:(?a)|(?b))\\k){2}"sv); auto subject = Utf16String::from_utf8("aabb"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 0, "aabb"sv); expect_capture_unmatched(regex, 1); expect_capture_eq(regex, subject, 2, "b"sv); } { auto regex = compile_regex("(?:(?a)|(?b))\\k"sv); auto subject = Utf16String::from_utf8("aa"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 0, "aa"sv); expect_capture_eq(regex, subject, 1, "a"sv); expect_capture_unmatched(regex, 2); } { auto regex = compile_regex("(.*?)a(?!(a+)b\\2c)\\2(.*)"sv); auto subject = Utf16String::from_utf8("baaabaac"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 0, "baaabaac"sv); expect_capture_eq(regex, subject, 1, "ba"sv); expect_capture_unmatched(regex, 2); expect_capture_eq(regex, subject, 3, "abaac"sv); } { auto regex = compile_regex("^(?:(?x)|(?y)|z)\\k$"sv); auto subject = Utf16String::from_utf8("z"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 0, "z"sv); expect_capture_unmatched(regex, 1); expect_capture_unmatched(regex, 2); } { auto regex = compile_regex("^(?:(?x)|(?y)|z){2}\\k$"sv); auto subject = Utf16String::from_utf8("xz"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 0, "xz"sv); expect_capture_unmatched(regex, 1); expect_capture_unmatched(regex, 2); } } TEST_CASE(restored_optional_groups_with_empty_matches) { { auto regex = compile_regex("^(.*)(.*)?$"sv); auto subject = Utf16String::from_utf8("a"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 1, "a"sv); expect_capture_unmatched(regex, 2); } { auto regex = compile_regex("()?"sv); auto subject = Utf16String::from_utf8(""sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_unmatched(regex, 1); } { auto regex = compile_regex("(z)((a+)?(b+)?(c))*"sv); auto subject = Utf16String::from_utf8("zaacbbbcac"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 1, "z"sv); expect_capture_eq(regex, subject, 2, "ac"sv); expect_capture_eq(regex, subject, 3, "a"sv); expect_capture_unmatched(regex, 4); expect_capture_eq(regex, subject, 5, "c"sv); } { auto regex = compile_regex("(?:(?=(abc)))?a"sv); auto subject = Utf16String::from_utf8("abc"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 0, "a"sv); expect_capture_unmatched(regex, 1); } { auto regex = compile_regex("^(?:(?=(abc))){0,1}a"sv); auto subject = Utf16String::from_utf8("abc"sv); EXPECT_EQ(regex.exec(subject, 0), regex::MatchResult::Match); expect_capture_eq(regex, subject, 0, "a"sv); expect_capture_unmatched(regex, 1); } } TEST_CASE(restored_ecmascript_modifier_coverage) { struct Test { StringView pattern; StringView subject; bool should_match { true }; regex::ECMAScriptCompileFlags flags {}; }; static constexpr Test tests[] { { "a(?i:b)c"sv, "aBc"sv }, { "a(?i:b)c"sv, "aBC"sv, false }, { "a(?s:.)c"sv, "a\nc"sv }, { "(?ims:a.b)"sv, "A\nB"sv }, { "(?i:a(?-i:b)c)"sv, "AbC"sv }, { "(?i:a(?-i:b)c)"sv, "ABC"sv, false }, { "a(?-i:b)c"sv, "AbC"sv, true, { .ignore_case = true } }, { "a(?-i:b)c"sv, "ABC"sv, false, { .ignore_case = true } }, { "x.(?m:^a)"sv, "x\na"sv, true, { .dot_all = true } }, }; for (auto const& test : tests) EXPECT_EQ(matches(test.pattern, test.subject, test.flags), test.should_match); } TEST_CASE(restored_unicode_property_and_sets_coverage) { struct Test { StringView pattern; StringView subject; bool should_match { true }; regex::ECMAScriptCompileFlags flags {}; }; static constexpr Test tests[] { { "\\p{ASCII}"sv, "a"sv, false }, { "\\p{ASCII}"sv, "p{ASCII}"sv }, { "\\p{ASCII}"sv, "a"sv, true, { .unicode = true } }, { "\\p{ASCII}"sv, "πŸ˜€"sv, false, { .unicode = true } }, { "\\P{ASCII}"sv, "a"sv, false, { .unicode = true } }, { "\\P{ASCII}"sv, "πŸ˜€"sv, true, { .unicode = true } }, { "\\p{ASCII_Hex_Digit}"sv, "1"sv, true, { .unicode = true } }, { "\\P{ASCII_Hex_Digit}"sv, "x"sv, true, { .unicode = true } }, { "\\p{General_Category=Cased_Letter}"sv, "A"sv, true, { .unicode = true } }, { "\\P{Cased_Letter}"sv, "9"sv, true, { .unicode = true } }, { "\\p{sc=Latin}"sv, "A"sv, true, { .unicode = true } }, { "\\u{1f600}"sv, "πŸ˜€"sv, true, { .unicode = true } }, { "[\\w--x]"sv, "x"sv, false, { .unicode_sets = true } }, { "[\\w--x]"sv, "y"sv, true, { .unicode_sets = true } }, { "[\\w&&x]"sv, "x"sv, true, { .unicode_sets = true } }, { "[[0-9\\w]--x--6]"sv, "6"sv, false, { .unicode_sets = true } }, { "[[0-9\\w]--x--6]"sv, "9"sv, true, { .unicode_sets = true } }, }; for (auto const& test : tests) EXPECT_EQ(matches(test.pattern, test.subject, test.flags), test.should_match); } TEST_CASE(restored_empty_match_and_loop_coverage) { static constexpr StringView patterns[] { "(a*)*"sv, "(a*?)*"sv, "(a*)*?"sv, "(?:)*?"sv, "(a?)+$"sv, }; for (auto pattern : patterns) EXPECT(matches(pattern, ""sv)); auto regex = compile_regex(".*"sv, { .global = true }); auto subject = Utf16String::from_utf8(""sv); EXPECT_EQ(regex.find_all(subject, 0), 1); EXPECT_EQ(regex.find_all_match(0).start, 0); EXPECT_EQ(regex.find_all_match(0).end, 0); } TEST_CASE(restored_long_fork_chain_coverage) { auto regex = compile_regex("(?:aa)*"sv); auto subject = MUST(String::repeated('a', 1000)); auto utf16_subject = Utf16String::from_utf8(subject.bytes_as_string_view()); EXPECT_EQ(regex.test(utf16_subject, 0), regex::MatchResult::Match); }