/* * Copyright (c) 2020, Emanuel Sprung * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include #include TEST_CASE(catch_all) { ByteString pattern = "^.*$"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "Hello World", 0, NULL, 0), REG_NOERR); regfree(®ex); } TEST_CASE(simple_start) { ByteString pattern = "^hello friends"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "Hello!", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello friends", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "Well, hello friends", 0, NULL, 0), REG_NOMATCH); regfree(®ex); } TEST_CASE(simple_end) { ByteString pattern = ".*hello\\.\\.\\. there$"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "Hallo", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "I said fyhello... there", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "ahello... therea", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello.. there", 0, NULL, 0), REG_NOMATCH); regfree(®ex); } TEST_CASE(simple_period) { ByteString pattern = "hello."; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "Hello1", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello1", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "hello2", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "hello?", 0, NULL, 0), REG_NOERR); regfree(®ex); } TEST_CASE(simple_period_end) { ByteString pattern = "hello.$"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED | REG_NOSUB), REG_NOERR); EXPECT_EQ(regexec(®ex, "Hello1", 0, NULL, REG_NOSUB), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello1hello1", 0, NULL, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "hello2hell", 0, NULL, REG_GLOBAL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello?", 0, NULL, REG_NOSUB), REG_NOERR); regfree(®ex); } TEST_CASE(simple_escaped) { ByteString pattern = "hello\\."; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "hello", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello.", 0, NULL, 0), REG_NOERR); regfree(®ex); } TEST_CASE(simple_period2_end) { ByteString pattern = ".*hi... there$"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "Hello there", 0, NULL, REG_GLOBAL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "I said fyhi... there", 0, NULL, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "....hi... ", 0, NULL, REG_GLOBAL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "I said fyhihii there", 0, NULL, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "I said fyhihi there", 0, NULL, REG_GLOBAL), REG_NOMATCH); regfree(®ex); } TEST_CASE(simple_plus) { ByteString pattern = "a+"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED | REG_NOSUB), REG_NOERR); EXPECT_EQ(regexec(®ex, "b", 0, NULL, REG_NOSUB), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "a", 0, NULL, REG_NOSUB), REG_NOERR); EXPECT_EQ(regexec(®ex, "aaaaaabbbbb", 0, NULL, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "aaaaaaaaaaa", 0, NULL, REG_GLOBAL), REG_NOERR); regfree(®ex); } TEST_CASE(simple_questionmark) { ByteString pattern = "da?d"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "a", 0, NULL, REG_GLOBAL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "daa", 0, NULL, REG_GLOBAL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "ddddd", 0, NULL, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "dd", 0, NULL, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "dad", 0, NULL, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "dada", 0, NULL, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "adadaa", 0, NULL, REG_GLOBAL), REG_NOERR); regfree(®ex); } TEST_CASE(simple_questionmark_matchall) { ByteString pattern = "da?d"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "a", num_matches, matches, REG_GLOBAL), REG_NOMATCH); EXPECT_EQ(matches[0].rm_cnt, 0); EXPECT_EQ(regexec(®ex, "daa", num_matches, matches, REG_GLOBAL), REG_NOMATCH); EXPECT_EQ(matches[0].rm_cnt, 0); EXPECT_EQ(regexec(®ex, "ddddd", num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 2); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 2); EXPECT_EQ(matches[1].rm_so, 2); EXPECT_EQ(matches[1].rm_eo, 4); EXPECT_EQ(regexec(®ex, "dd", num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(regexec(®ex, "dad", num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(regexec(®ex, "dada", num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(regexec(®ex, "adadaa", num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); regfree(®ex); } TEST_CASE(character_class) { ByteString pattern = "[[:alpha:]]"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; ByteString haystack = "[Window]\nOpacity=255\nAudibleBeep=0\n"; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, haystack.characters(), num_matches, matches, 0), REG_NOMATCH); EXPECT_EQ(matches[0].rm_cnt, 0); EXPECT_EQ(regexec(®ex, haystack.characters(), num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 24); EXPECT_EQ(haystack.substring_view(matches[0].rm_so, matches[0].rm_eo - matches[0].rm_so), "W"); EXPECT_EQ(haystack.substring_view(matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so), "i"); regfree(®ex); } TEST_CASE(character_class2) { ByteString pattern = "[[:alpha:]]*=([[:digit:]]*)|\\[(.*)\\]"; regex_t regex; static constexpr int num_matches { 9 }; regmatch_t matches[num_matches]; ByteString haystack = "[Window]\nOpacity=255\nAudibleBeep=0\n"; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED | REG_NEWLINE), REG_NOERR); EXPECT_EQ(regexec(®ex, haystack.characters(), num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 3); #if 0 for (int i = 0; i < num_matches; ++i) { fprintf(stderr, "Matches[%i].rm_so: %li, .rm_eo: %li .rm_cnt: %li: ", i, matches[i].rm_so, matches[i].rm_eo, matches[i].rm_cnt); fprintf(stderr, "haystack length: %lu\n", haystack.length()); if (matches[i].rm_so != -1) fprintf(stderr, "%s\n", haystack.substring_view(matches[i].rm_so, matches[i].rm_eo - matches[i].rm_so).to_byte_string().characters()); } #endif EXPECT_EQ(haystack.substring_view(matches[0].rm_so, matches[0].rm_eo - matches[0].rm_so), "[Window]"); EXPECT_EQ(matches[1].rm_so, -1); EXPECT_EQ(matches[1].rm_eo, -1); EXPECT_EQ(matches[1].rm_cnt, 0); EXPECT_EQ(haystack.substring_view(matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so), "Window"); EXPECT_EQ(haystack.substring_view(matches[3].rm_so, matches[3].rm_eo - matches[3].rm_so), "Opacity=255"); EXPECT_EQ(haystack.substring_view(matches[4].rm_so, matches[4].rm_eo - matches[4].rm_so), "255"); EXPECT_EQ(matches[5].rm_so, -1); EXPECT_EQ(matches[5].rm_eo, -1); EXPECT_EQ(matches[5].rm_cnt, 0); EXPECT_EQ(haystack.substring_view(matches[6].rm_so, matches[6].rm_eo - matches[6].rm_so), "AudibleBeep=0"); EXPECT_EQ(haystack.substring_view(matches[7].rm_so, matches[7].rm_eo - matches[7].rm_so), "0"); EXPECT_EQ(matches[8].rm_so, -1); EXPECT_EQ(matches[8].rm_eo, -1); EXPECT_EQ(matches[8].rm_cnt, 0); regfree(®ex); } TEST_CASE(escaped_char_questionmark) { ByteString pattern = "This\\.?And\\.?That"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "ThisAndThat", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "This.And.That", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "This And That", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "This..And..That", 0, NULL, 0), REG_NOMATCH); regfree(®ex); } TEST_CASE(char_qualifier_asterisk) { ByteString pattern = "regex*"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "#include ", num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); regfree(®ex); } TEST_CASE(char_utf8) { ByteString pattern = "😀"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "Привет, мир! 😀 γειά σου κόσμος 😀 こんにちは世界", num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 2); regfree(®ex); } TEST_CASE(parens) { ByteString pattern = "test(hello)test"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "testhellotest", num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 13); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 9); regfree(®ex); } TEST_CASE(parser_error_parens) { ByteString pattern = "test()test"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR); EXPECT_EQ(regexec(®ex, "testhellotest", num_matches, matches, 0), REG_EMPTY_EXPR); regfree(®ex); } TEST_CASE(parser_error_special_characters_used_at_wrong_place) { ByteString pattern; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; Vector chars = { '*', '+', '?', '}' }; StringBuilder b; for (auto& ch : chars) { auto error_code_to_check = ch == '}' ? REG_EBRACE : REG_BADRPT; // First in ere b.clear(); b.append(ch); pattern = b.to_byte_string(); EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), error_code_to_check); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), error_code_to_check); regfree(®ex); // After vertical line b.clear(); b.append("a|"sv); b.append(ch); pattern = b.to_byte_string(); EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), error_code_to_check); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), error_code_to_check); regfree(®ex); // After circumflex b.clear(); b.append('^'); b.append(ch); pattern = b.to_byte_string(); EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), error_code_to_check); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), error_code_to_check); regfree(®ex); // After dollar b.clear(); b.append('$'); b.append(ch); pattern = b.to_byte_string(); EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), error_code_to_check); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), error_code_to_check); regfree(®ex); // After left parens b.clear(); b.append('('); b.append(ch); b.append(')'); pattern = b.to_byte_string(); EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), error_code_to_check); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), error_code_to_check); regfree(®ex); } } TEST_CASE(parser_error_vertical_line_used_at_wrong_place) { ByteString pattern; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; // First in ere pattern = "|asdf"; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), REG_EMPTY_EXPR); regfree(®ex); // Last in ere pattern = "asdf|"; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), REG_EMPTY_EXPR); regfree(®ex); // After left parens pattern = "(|asdf)"; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), REG_EMPTY_EXPR); regfree(®ex); // Proceed right parens pattern = "(asdf)|"; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), REG_EMPTY_EXPR); regfree(®ex); } TEST_CASE(parens_qualifier_questionmark) { ByteString pattern = "test(hello)?test"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; char const* match_str; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); match_str = "testtest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 8); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testtest"); match_str = "testhellotest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 13); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 9); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testhellotest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); regfree(®ex); } TEST_CASE(parens_qualifier_asterisk) { ByteString pattern = "test(hello)*test"; regex_t regex; static constexpr int num_matches { 6 }; regmatch_t matches[num_matches]; char const* match_str; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); match_str = "testtest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 8); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testtest"); match_str = "testhellohellotest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 18); EXPECT_EQ(matches[1].rm_so, 9); EXPECT_EQ(matches[1].rm_eo, 14); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testhellohellotest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); match_str = "testhellohellotest, testhellotest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 2); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 18); EXPECT_EQ(matches[1].rm_so, 9); EXPECT_EQ(matches[1].rm_eo, 14); EXPECT_EQ(matches[2].rm_so, 20); EXPECT_EQ(matches[2].rm_eo, 33); EXPECT_EQ(matches[3].rm_so, 24); EXPECT_EQ(matches[3].rm_eo, 29); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testhellohellotest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), "testhellotest"); EXPECT_EQ(StringView(&match_str[matches[3].rm_so], matches[3].rm_eo - matches[3].rm_so), "hello"); regfree(®ex); } TEST_CASE(parens_qualifier_asterisk_2) { ByteString pattern = "test(.*)test"; regex_t regex; static constexpr int num_matches { 6 }; regmatch_t matches[num_matches]; char const* match_str; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); match_str = "testasdftest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 12); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 8); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testasdftest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "asdf"); match_str = "testasdfasdftest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 16); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 12); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testasdfasdftest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "asdfasdf"); match_str = "testaaaatest, testbbbtest, testtest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 35); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 31); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testaaaatest, testbbbtest, testtest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "aaaatest, testbbbtest, test"); regfree(®ex); } TEST_CASE(mulit_parens_qualifier_too_less_result_values) { ByteString pattern = "test(a)?(b)?(c)?test"; regex_t regex; static constexpr int num_matches { 4 }; regmatch_t matches[num_matches]; char const* match_str; matches[3] = { -2, -2, 100 }; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); match_str = "testabtest"; EXPECT_EQ(regexec(®ex, match_str, num_matches - 1, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 10); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 5); EXPECT_EQ(matches[2].rm_so, 5); EXPECT_EQ(matches[2].rm_eo, 6); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testabtest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "a"); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), "b"); EXPECT_EQ(matches[3].rm_so, -2); EXPECT_EQ(matches[3].rm_eo, -2); EXPECT_EQ(matches[3].rm_cnt, 100); match_str = "testabctest"; EXPECT_EQ(regexec(®ex, match_str, num_matches - 1, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 11); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 5); EXPECT_EQ(matches[2].rm_so, 5); EXPECT_EQ(matches[2].rm_eo, 6); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testabctest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "a"); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), "b"); EXPECT_EQ(matches[3].rm_so, -2); EXPECT_EQ(matches[3].rm_eo, -2); EXPECT_EQ(matches[3].rm_cnt, 100); match_str = "testabctest, testabctest"; EXPECT_EQ(regexec(®ex, match_str, num_matches - 1, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 2); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 11); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 5); EXPECT_EQ(matches[2].rm_so, 5); EXPECT_EQ(matches[2].rm_eo, 6); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testabctest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "a"); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), "b"); EXPECT_EQ(matches[3].rm_so, -2); EXPECT_EQ(matches[3].rm_eo, -2); EXPECT_EQ(matches[3].rm_cnt, 100); regfree(®ex); } TEST_CASE(multi_parens_qualifier_questionmark) { ByteString pattern = "test(a)?(b)?(c)?test"; regex_t regex; static constexpr int num_matches { 8 }; regmatch_t matches[num_matches]; char const* match_str; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); match_str = "testtest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 8); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testtest"); match_str = "testabctest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 11); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 5); EXPECT_EQ(matches[2].rm_so, 5); EXPECT_EQ(matches[2].rm_eo, 6); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testabctest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "a"); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), "b"); match_str = "testabctest, testactest"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 2); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 11); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 5); EXPECT_EQ(matches[2].rm_so, 5); EXPECT_EQ(matches[2].rm_eo, 6); EXPECT_EQ(matches[3].rm_so, 6); EXPECT_EQ(matches[3].rm_eo, 7); EXPECT_EQ(matches[4].rm_so, 13); EXPECT_EQ(matches[4].rm_eo, 23); EXPECT_EQ(matches[5].rm_so, 17); EXPECT_EQ(matches[5].rm_eo, 18); EXPECT_EQ(matches[6].rm_so, -1); EXPECT_EQ(matches[6].rm_eo, -1); EXPECT_EQ(matches[7].rm_so, 18); EXPECT_EQ(matches[7].rm_eo, 19); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testabctest"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "a"); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), "b"); EXPECT_EQ(StringView(&match_str[matches[3].rm_so], matches[3].rm_eo - matches[3].rm_so), "c"); EXPECT_EQ(StringView(&match_str[matches[4].rm_so], matches[4].rm_eo - matches[4].rm_so), "testactest"); EXPECT_EQ(StringView(&match_str[matches[5].rm_so], matches[5].rm_eo - matches[5].rm_so), "a"); EXPECT_EQ(StringView(&match_str[matches[6].rm_so], matches[6].rm_eo - matches[6].rm_so), ""); EXPECT_EQ(StringView(&match_str[matches[7].rm_so], matches[7].rm_eo - matches[7].rm_so), "c"); regfree(®ex); } TEST_CASE(simple_alternative) { ByteString pattern = "test|hello|friends"; regex_t regex; static constexpr int num_matches { 1 }; regmatch_t matches[num_matches]; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "test", num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 4); EXPECT_EQ(regexec(®ex, "hello", num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 5); EXPECT_EQ(regexec(®ex, "friends", num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 7); regfree(®ex); } TEST_CASE(alternative_match_groups) { ByteString pattern = "test(a)?(b)?|hello ?(dear|my)? friends"; regex_t regex; static constexpr int num_matches { 8 }; regmatch_t matches[num_matches]; char const* match_str; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); match_str = "test"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 4); EXPECT_EQ(matches[1].rm_so, -1); EXPECT_EQ(matches[1].rm_eo, -1); EXPECT_EQ(matches[2].rm_so, -1); EXPECT_EQ(matches[2].rm_eo, -1); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "test"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), ""); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), ""); match_str = "testa"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 5); EXPECT_EQ(matches[1].rm_so, 4); EXPECT_EQ(matches[1].rm_eo, 5); EXPECT_EQ(matches[2].rm_so, -1); EXPECT_EQ(matches[2].rm_eo, -1); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testa"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "a"); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), ""); match_str = "testb"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 5); EXPECT_EQ(matches[1].rm_so, -1); EXPECT_EQ(matches[1].rm_eo, -1); EXPECT_EQ(matches[2].rm_so, 4); EXPECT_EQ(matches[2].rm_eo, 5); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "testb"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), ""); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), "b"); match_str = "hello friends"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 13); EXPECT_EQ(matches[1].rm_so, -1); EXPECT_EQ(matches[1].rm_eo, -1); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hello friends"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), ""); match_str = "hello dear friends"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 18); EXPECT_EQ(matches[1].rm_so, -1); EXPECT_EQ(matches[1].rm_eo, -1); EXPECT_EQ(matches[2].rm_so, -1); EXPECT_EQ(matches[2].rm_eo, -1); EXPECT_EQ(matches[3].rm_so, 6); EXPECT_EQ(matches[3].rm_eo, 10); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hello dear friends"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), ""); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), ""); EXPECT_EQ(StringView(&match_str[matches[3].rm_so], matches[3].rm_eo - matches[3].rm_so), "dear"); match_str = "hello my friends"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 16); EXPECT_EQ(matches[1].rm_so, -1); EXPECT_EQ(matches[1].rm_eo, -1); EXPECT_EQ(matches[2].rm_so, -1); EXPECT_EQ(matches[2].rm_eo, -1); EXPECT_EQ(matches[3].rm_so, 6); EXPECT_EQ(matches[3].rm_eo, 8); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hello my friends"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), ""); EXPECT_EQ(StringView(&match_str[matches[2].rm_so], matches[2].rm_eo - matches[2].rm_so), ""); EXPECT_EQ(StringView(&match_str[matches[3].rm_so], matches[3].rm_eo - matches[3].rm_so), "my"); match_str = "testabc"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOMATCH); EXPECT_EQ(matches[0].rm_cnt, 0); EXPECT_EQ(matches[0].rm_so, -1); EXPECT_EQ(matches[0].rm_eo, -1); match_str = "hello test friends"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOMATCH); EXPECT_EQ(matches[0].rm_cnt, 0); EXPECT_EQ(matches[0].rm_so, -1); EXPECT_EQ(matches[0].rm_eo, -1); regfree(®ex); } TEST_CASE(parens_qualifier_exact) { ByteString pattern = "(hello){3}"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; char const* match_str; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); match_str = "hello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOMATCH); EXPECT_EQ(matches[0].rm_cnt, 0); match_str = "hellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 15); EXPECT_EQ(matches[1].rm_so, 10); EXPECT_EQ(matches[1].rm_eo, 15); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); match_str = "hellohellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 15); EXPECT_EQ(matches[1].rm_so, 10); EXPECT_EQ(matches[1].rm_eo, 15); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); match_str = "test hellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 5); EXPECT_EQ(matches[0].rm_eo, 20); EXPECT_EQ(matches[1].rm_so, 15); EXPECT_EQ(matches[1].rm_eo, 20); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); regfree(®ex); } TEST_CASE(parens_qualifier_minimum) { ByteString pattern = "(hello){3,}"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; char const* match_str; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); match_str = "hello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOMATCH); EXPECT_EQ(matches[0].rm_cnt, 0); match_str = "hellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 15); EXPECT_EQ(matches[1].rm_so, 10); EXPECT_EQ(matches[1].rm_eo, 15); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); match_str = "hellohellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_SEARCH), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 20); EXPECT_EQ(matches[1].rm_so, 15); EXPECT_EQ(matches[1].rm_eo, 20); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); match_str = "test hellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 5); EXPECT_EQ(matches[0].rm_eo, 20); EXPECT_EQ(matches[1].rm_so, 15); EXPECT_EQ(matches[1].rm_eo, 20); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); match_str = "test hellohellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 5); EXPECT_EQ(matches[0].rm_eo, 25); EXPECT_EQ(matches[1].rm_so, 20); EXPECT_EQ(matches[1].rm_eo, 25); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); regfree(®ex); } TEST_CASE(parens_qualifier_maximum) { ByteString pattern = "(hello){2,3}"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; char const* match_str; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); match_str = "hello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOMATCH); EXPECT_EQ(matches[0].rm_cnt, 0); match_str = "hellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 15); EXPECT_EQ(matches[1].rm_so, 10); EXPECT_EQ(matches[1].rm_eo, 15); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); match_str = "hellohellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 0); EXPECT_EQ(matches[0].rm_eo, 15); EXPECT_EQ(matches[1].rm_so, 10); EXPECT_EQ(matches[1].rm_eo, 15); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); match_str = "test hellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 5); EXPECT_EQ(matches[0].rm_eo, 20); EXPECT_EQ(matches[1].rm_so, 15); EXPECT_EQ(matches[1].rm_eo, 20); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); match_str = "test hellohellohellohello"; EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(matches[0].rm_so, 5); EXPECT_EQ(matches[0].rm_eo, 20); EXPECT_EQ(matches[1].rm_so, 15); EXPECT_EQ(matches[1].rm_eo, 20); EXPECT_EQ(StringView(&match_str[matches[0].rm_so], matches[0].rm_eo - matches[0].rm_so), "hellohellohello"); EXPECT_EQ(StringView(&match_str[matches[1].rm_so], matches[1].rm_eo - matches[1].rm_so), "hello"); regfree(®ex); } TEST_CASE(char_qualifier_min_max) { ByteString pattern = "c{3,30}"; regex_t regex; static constexpr int num_matches { 5 }; regmatch_t matches[num_matches]; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "cc", num_matches, matches, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "ccc", num_matches, matches, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "cccccccccccccccccccccccccccccc", num_matches, matches, 0), REG_NOERR); EXPECT_EQ(matches[0].rm_cnt, 1); EXPECT_EQ(regexec(®ex, "ccccccccccccccccccccccccccccccc", num_matches, matches, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "ccccccccccccccccccccccccccccccc", num_matches, matches, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "cccccccccccccccccccccccccccccccc", num_matches, matches, 0), REG_NOMATCH); regfree(®ex); } TEST_CASE(simple_bracket_chars) { ByteString pattern = "[abc]"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "a", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "b", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "c", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "d", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "e", 0, NULL, 0), REG_NOMATCH); regfree(®ex); } TEST_CASE(simple_bracket_chars_inverse) { ByteString pattern = "[^abc]"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "a", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "b", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "c", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "d", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "e", 0, NULL, 0), REG_NOERR); regfree(®ex); } TEST_CASE(simple_bracket_chars_range) { ByteString pattern = "[a-d]"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "a", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "b", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "c", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "d", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "e", 0, NULL, 0), REG_NOMATCH); regfree(®ex); } TEST_CASE(simple_bracket_chars_range_inverse) { ByteString pattern = "[^a-df-z]"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "a", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "b", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "c", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "d", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "e", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "k", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "z", 0, NULL, 0), REG_NOMATCH); regfree(®ex); } TEST_CASE(bracket_character_class_uuid) { ByteString pattern = "^([[:xdigit:]]{8})-([[:xdigit:]]{4})-([[:xdigit:]]{4})-([[:xdigit:]]{4})-([[:xdigit:]]{12})$"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "fb9b62a2-1579-4e3a-afba-76239ccb6583", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "fb9b62a2", 0, NULL, 0), REG_NOMATCH); regfree(®ex); } TEST_CASE(simple_bracket_character_class_inverse) { ByteString pattern = "[^[:digit:]]"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "1", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "2", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "3", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "d", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "e", 0, NULL, 0), REG_NOERR); regfree(®ex); } TEST_CASE(email_address) { ByteString pattern = "^[A-Z0-9a-z._%+-]{1,64}@(?:[A-Za-z0-9-]{1,63}\\.){1,125}[A-Za-z]{2,63}$"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_NOERR); EXPECT_EQ(regexec(®ex, "emanuel.sprung@gmail.com", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "kling@serenityos.org", 0, NULL, 0), REG_NOERR); regfree(®ex); } TEST_CASE(error_message) { ByteString pattern = "^[A-Z0-9[a-z._%+-]{1,64}@[A-Za-z0-9-]{1,63}\\.{1,125}[A-Za-z]{2,63}$"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED), REG_EBRACK); EXPECT_EQ(regexec(®ex, "asdf@asdf.com", 0, NULL, 0), REG_EBRACK); char buf[1024]; size_t buflen = 1024; auto len = regerror(0, ®ex, buf, buflen); ByteString expected = "Error during parsing of regular expression:\n ^[A-Z0-9[a-z._%+-]{1,64}@[A-Za-z0-9-]{1,63}\\.{1,125}[A-Za-z]{2,63}$\n ^---- [ ] imbalance."; for (size_t i = 0; i < len; ++i) { EXPECT_EQ(buf[i], expected[i]); } regfree(®ex); } TEST_CASE(simple_ignorecase) { ByteString pattern = "^hello friends"; regex_t regex; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR); EXPECT_EQ(regexec(®ex, "Hello Friends", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "hello Friends", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "hello Friends!", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello Friends!", 0, NULL, REG_GLOBAL), REG_NOERR); EXPECT_EQ(regexec(®ex, "hell Friends", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hell Friends", 0, NULL, REG_GLOBAL), REG_NOMATCH); regfree(®ex); } TEST_CASE(simple_notbol_noteol) { ByteString pattern = "^hello friends$"; ByteString pattern2 = "hello friends"; regex_t regex, regex2; EXPECT_EQ(regcomp(®ex, pattern.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR); EXPECT_EQ(regcomp(®ex2, pattern2.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR); EXPECT_EQ(regexec(®ex, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello friends", 0, NULL, REG_NOTBOL | REG_NOTEOL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "a hello friends b", 0, NULL, REG_NOTBOL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "a hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "a hello friends", 0, NULL, REG_NOTBOL | REG_SEARCH), REG_NOERR); EXPECT_EQ(regexec(®ex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_SEARCH), REG_NOERR); EXPECT_EQ(regexec(®ex, "a hello friends b", 0, NULL, REG_NOTEOL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello friends b", 0, NULL, REG_NOTEOL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "hello friends b", 0, NULL, REG_NOTEOL | REG_SEARCH), REG_NOERR); EXPECT_EQ(regexec(®ex, "a hello friends b", 0, NULL, REG_NOTEOL | REG_SEARCH), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL | REG_SEARCH), REG_NOMATCH); EXPECT_EQ(regexec(®ex2, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH); EXPECT_EQ(regexec(®ex2, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH); regfree(®ex); regfree(®ex2); } TEST_CASE(bre_basic) { regex_t regex; EXPECT_EQ(regcomp(®ex, "hello friends", REG_NOSUB | REG_ICASE), REG_NOERR); EXPECT_EQ(regexec(®ex, "hello friends", 0, NULL, 0), REG_NOERR); regfree(®ex); EXPECT_EQ(regcomp(®ex, "\\(15\\)\\1", REG_NOSUB | REG_ICASE), REG_NOERR); EXPECT_EQ(regexec(®ex, "1515", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "55", 0, NULL, 0), REG_NOMATCH); regfree(®ex); EXPECT_EQ(regcomp(®ex, "15\\{1,2\\}", REG_NOSUB | REG_ICASE), REG_NOERR); EXPECT_EQ(regexec(®ex, "15", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "1515", 0, NULL, 0), REG_NOMATCH); EXPECT_EQ(regexec(®ex, "55", 0, NULL, 0), REG_NOMATCH); regfree(®ex); EXPECT_EQ(regcomp(®ex, "15{1,2}", REG_NOSUB | REG_ICASE), REG_NOERR); EXPECT_EQ(regexec(®ex, "15{1,2}", 0, NULL, 0), REG_NOERR); regfree(®ex); EXPECT_EQ(regcomp(®ex, "1[56]", REG_NOSUB | REG_ICASE), REG_NOERR); EXPECT_EQ(regexec(®ex, "15", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "16", 0, NULL, 0), REG_NOERR); EXPECT_EQ(regexec(®ex, "17", 0, NULL, 0), REG_NOMATCH); regfree(®ex); }