mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:32:46 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1140 lines
		
	
	
	
		
			45 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1140 lines
		
	
	
	
		
			45 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | ||
|  * Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com>
 | ||
|  * All rights reserved.
 | ||
|  *
 | ||
|  * Redistribution and use in source and binary forms, with or without
 | ||
|  * modification, are permitted provided that the following conditions are met:
 | ||
|  *
 | ||
|  * 1. Redistributions of source code must retain the above copyright notice, this
 | ||
|  *    list of conditions and the following disclaimer.
 | ||
|  *
 | ||
|  * 2. Redistributions in binary form must reproduce the above copyright notice,
 | ||
|  *    this list of conditions and the following disclaimer in the documentation
 | ||
|  *    and/or other materials provided with the distribution.
 | ||
|  *
 | ||
|  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | ||
|  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | ||
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | ||
|  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 | ||
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | ||
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 | ||
|  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 | ||
|  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 | ||
|  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | ||
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | ||
|  */
 | ||
| 
 | ||
| #include <AK/TestSuite.h>
 | ||
| 
 | ||
| #include <AK/StringBuilder.h>
 | ||
| #include <LibC/regex.h>
 | ||
| #include <stdio.h>
 | ||
| 
 | ||
| TEST_CASE(catch_all)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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, 0u);
 | ||
|     EXPECT_EQ(regexec(®ex, "daa", num_matches, matches, REG_GLOBAL), REG_NOMATCH);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 0u);
 | ||
| 
 | ||
|     EXPECT_EQ(regexec(®ex, "ddddd", num_matches, matches, REG_GLOBAL), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 2u);
 | ||
| 
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 2u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 2u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 4u);
 | ||
| 
 | ||
|     EXPECT_EQ(regexec(®ex, "dd", num_matches, matches, REG_GLOBAL), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
|     EXPECT_EQ(regexec(®ex, "dad", num_matches, matches, REG_GLOBAL), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
|     EXPECT_EQ(regexec(®ex, "dada", num_matches, matches, REG_GLOBAL), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
|     EXPECT_EQ(regexec(®ex, "adadaa", num_matches, matches, REG_GLOBAL), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
| 
 | ||
|     regfree(®ex);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(character_class)
 | ||
| {
 | ||
|     String pattern = "[[:alpha:]]";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 5 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
| 
 | ||
|     String 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, 0u);
 | ||
|     EXPECT_EQ(regexec(®ex, haystack.characters(), num_matches, matches, REG_GLOBAL), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 24u);
 | ||
|     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)
 | ||
| {
 | ||
|     String pattern = "[[:alpha:]]*=([[:digit:]]*)|\\[(.*)\\]";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 9 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
| 
 | ||
|     String 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, 3u);
 | ||
| #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_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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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 <regex.h>", num_matches, matches, REG_GLOBAL), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
| 
 | ||
|     regfree(®ex);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(char_utf8)
 | ||
| {
 | ||
|     String 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, 2u);
 | ||
| 
 | ||
|     regfree(®ex);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(parens)
 | ||
| {
 | ||
|     String 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, 1u);
 | ||
| 
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 13u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 9u);
 | ||
| 
 | ||
|     regfree(®ex);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(parser_error_parens)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String pattern;
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 5 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
| 
 | ||
|     Vector<char, 4> 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.build();
 | ||
|         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);
 | ||
| 
 | ||
|         // After vertical line
 | ||
|         b.clear();
 | ||
|         b.append("a|");
 | ||
|         b.append(ch);
 | ||
|         pattern = b.build();
 | ||
|         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);
 | ||
| 
 | ||
|         // After circumflex
 | ||
|         b.clear();
 | ||
|         b.append("^");
 | ||
|         b.append(ch);
 | ||
|         pattern = b.build();
 | ||
|         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);
 | ||
| 
 | ||
|         // After dollar
 | ||
|         b.clear();
 | ||
|         b.append("$");
 | ||
|         b.append(ch);
 | ||
|         pattern = b.build();
 | ||
|         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);
 | ||
| 
 | ||
|         // After left parens
 | ||
|         b.clear();
 | ||
|         b.append("(");
 | ||
|         b.append(ch);
 | ||
|         b.append(")");
 | ||
|         pattern = b.build();
 | ||
|         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)
 | ||
| {
 | ||
|     String 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);
 | ||
| 
 | ||
|     // 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);
 | ||
| 
 | ||
|     // 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);
 | ||
| 
 | ||
|     // 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)
 | ||
| {
 | ||
|     String pattern = "test(hello)?test";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 5 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
|     const char* 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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 8u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 13u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 9u);
 | ||
|     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)
 | ||
| {
 | ||
|     String pattern = "test(hello)*test";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 6 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
|     const char* 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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 8u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 18u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 9u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 14u);
 | ||
|     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, 2u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 18u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 9u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 14u);
 | ||
|     EXPECT_EQ(matches[2].rm_so, 20u);
 | ||
|     EXPECT_EQ(matches[2].rm_eo, 33u);
 | ||
|     EXPECT_EQ(matches[3].rm_so, 24u);
 | ||
|     EXPECT_EQ(matches[3].rm_eo, 29u);
 | ||
|     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)
 | ||
| {
 | ||
|     String pattern = "test(.*)test";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 6 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
|     const char* 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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 12u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 8u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 16u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 12u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 35u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 31u);
 | ||
| 
 | ||
|     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)
 | ||
| {
 | ||
|     String pattern = "test(a)?(b)?(c)?test";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 4 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
|     const char* 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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 10u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_eo, 6u);
 | ||
|     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, 100u);
 | ||
| 
 | ||
|     match_str = "testabctest";
 | ||
|     EXPECT_EQ(regexec(®ex, match_str, num_matches - 1, matches, 0), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 11u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_eo, 6u);
 | ||
|     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, 100u);
 | ||
| 
 | ||
|     match_str = "testabctest, testabctest";
 | ||
| 
 | ||
|     EXPECT_EQ(regexec(®ex, match_str, num_matches - 1, matches, REG_GLOBAL), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 2u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 11u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_eo, 6u);
 | ||
|     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, 100u);
 | ||
| 
 | ||
|     regfree(®ex);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(multi_parens_qualifier_questionmark)
 | ||
| {
 | ||
|     String pattern = "test(a)?(b)?(c)?test";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 8 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
|     const char* 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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 8u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 11u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_eo, 6u);
 | ||
|     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, 2u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 11u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[2].rm_eo, 6u);
 | ||
|     EXPECT_EQ(matches[3].rm_so, 6u);
 | ||
|     EXPECT_EQ(matches[3].rm_eo, 7u);
 | ||
| 
 | ||
|     EXPECT_EQ(matches[4].rm_so, 13u);
 | ||
|     EXPECT_EQ(matches[4].rm_eo, 23u);
 | ||
|     EXPECT_EQ(matches[5].rm_so, 17u);
 | ||
|     EXPECT_EQ(matches[5].rm_eo, 18u);
 | ||
|     EXPECT_EQ(matches[6].rm_so, -1);
 | ||
|     EXPECT_EQ(matches[6].rm_eo, -1);
 | ||
|     EXPECT_EQ(matches[7].rm_so, 18u);
 | ||
|     EXPECT_EQ(matches[7].rm_eo, 19u);
 | ||
| 
 | ||
|     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)
 | ||
| {
 | ||
|     String 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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 4u);
 | ||
| 
 | ||
|     EXPECT_EQ(regexec(®ex, "hello", num_matches, matches, 0), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 5u);
 | ||
| 
 | ||
|     EXPECT_EQ(regexec(®ex, "friends", num_matches, matches, 0), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 7u);
 | ||
| 
 | ||
|     regfree(®ex);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(alternative_match_groups)
 | ||
| {
 | ||
|     String pattern = "test(a)?(b)?|hello ?(dear|my)? friends";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 8 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
|     const char* 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, 1u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 5u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 5u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 5u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, -1);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, -1);
 | ||
|     EXPECT_EQ(matches[2].rm_so, 4u);
 | ||
|     EXPECT_EQ(matches[2].rm_eo, 5u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 13u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 18u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 16u);
 | ||
|     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, 0u);
 | ||
|     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, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, -1);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, -1);
 | ||
| 
 | ||
|     regfree(®ex);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(parens_qualifier_exact)
 | ||
| {
 | ||
|     String pattern = "(hello){3}";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 5 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
|     const char* 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, 0u);
 | ||
| 
 | ||
|     match_str = "hellohellohello";
 | ||
|     EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 10u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 15u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 10u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 15u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 20u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 20u);
 | ||
|     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)
 | ||
| {
 | ||
|     String pattern = "(hello){3,}";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 5 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
|     const char* 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, 0u);
 | ||
| 
 | ||
|     match_str = "hellohellohello";
 | ||
|     EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 10u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 15u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 20u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 20u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 20u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 20u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 25u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 20u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 25u);
 | ||
|     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)
 | ||
| {
 | ||
|     String pattern = "(hello){2,3}";
 | ||
|     regex_t regex;
 | ||
|     static constexpr int num_matches { 5 };
 | ||
|     regmatch_t matches[num_matches];
 | ||
|     const char* 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, 0u);
 | ||
| 
 | ||
|     match_str = "hellohellohello";
 | ||
|     EXPECT_EQ(regexec(®ex, match_str, num_matches, matches, 0), REG_NOERR);
 | ||
|     EXPECT_EQ(matches[0].rm_cnt, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 10u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 15u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 0u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 10u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 15u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 20u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 20u);
 | ||
|     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, 1u);
 | ||
|     EXPECT_EQ(matches[0].rm_so, 5u);
 | ||
|     EXPECT_EQ(matches[0].rm_eo, 20u);
 | ||
|     EXPECT_EQ(matches[1].rm_so, 15u);
 | ||
|     EXPECT_EQ(matches[1].rm_eo, 20u);
 | ||
|     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)
 | ||
| {
 | ||
|     String 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, 1u);
 | ||
|     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)
 | ||
| {
 | ||
|     String 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);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(simple_bracket_chars_inverse)
 | ||
| {
 | ||
|     String 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);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(simple_bracket_chars_range)
 | ||
| {
 | ||
|     String 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);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(simple_bracket_chars_range_inverse)
 | ||
| {
 | ||
|     String 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);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(bracket_character_class_uuid)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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);
 | ||
| }
 | ||
| 
 | ||
| TEST_CASE(email_address)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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);
 | ||
|     String 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)
 | ||
| {
 | ||
|     String 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)
 | ||
| {
 | ||
|     String pattern = "^hello friends$";
 | ||
|     String 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);
 | ||
| }
 | ||
| 
 | ||
| TEST_MAIN(Regex)
 | 
