1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-22 02:05:07 +00:00
serenity/Userland/Libraries/LibRegex/Tests/RegexLibC.cpp
Andrew Kaster 35c0a6c54d AK+Userland: Move AK/TestSuite.h into LibTest and rework Tests' CMake
As many macros as possible are moved to Macros.h, while the
macros to create a test case are moved to TestCase.h. TestCase is now
the only user-facing header for creating a test case. TestSuite and its
helpers have moved into a .cpp file. Instead of requiring a TEST_MAIN
macro to be instantiated into the test file, a TestMain.cpp file is
provided instead that will be linked against each test. This has the
side effect that, if we wanted to have test cases split across multiple
files, it's as simple as adding them all to the same executable.

The test main should be portable to kernel mode as well, so if
there's a set of tests that should be run in self-test mode in kernel
space, we can accomodate that.

A new serenity_test CMake function streamlines adding a new test with
arguments for the test source file, subdirectory under /usr/Tests to
install the test application and an optional list of libraries to link
against the test application. To accomodate future test where the
provided TestMain.cpp is not suitable (e.g. test-js), a CUSTOM_MAIN
parameter can be passed to the function to not link against the
boilerplate main function.
2021-04-25 09:36:49 +02:00

1118 lines
44 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2020, Emanuel Sprung <emanuel.sprung@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibTest/TestCase.h>
#include <AK/StringBuilder.h>
#include <LibC/regex.h>
#include <stdio.h>
TEST_CASE(catch_all)
{
String pattern = "^.*$";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "Hello World", 0, NULL, 0), REG_NOERR);
regfree(&regex);
}
TEST_CASE(simple_start)
{
String pattern = "^hello friends";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "Hello!", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "Well, hello friends", 0, NULL, 0), REG_NOMATCH);
regfree(&regex);
}
TEST_CASE(simple_end)
{
String pattern = ".*hello\\.\\.\\. there$";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "Hallo", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "I said fyhello... there", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "ahello... therea", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello.. there", 0, NULL, 0), REG_NOMATCH);
regfree(&regex);
}
TEST_CASE(simple_period)
{
String pattern = "hello.";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "Hello1", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello1", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hello2", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hello?", 0, NULL, 0), REG_NOERR);
regfree(&regex);
}
TEST_CASE(simple_period_end)
{
String pattern = "hello.$";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED | REG_NOSUB), REG_NOERR);
EXPECT_EQ(regexec(&regex, "Hello1", 0, NULL, REG_NOSUB), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello1hello1", 0, NULL, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hello2hell", 0, NULL, REG_GLOBAL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello?", 0, NULL, REG_NOSUB), REG_NOERR);
regfree(&regex);
}
TEST_CASE(simple_escaped)
{
String pattern = "hello\\.";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hello", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello.", 0, NULL, 0), REG_NOERR);
regfree(&regex);
}
TEST_CASE(simple_period2_end)
{
String pattern = ".*hi... there$";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "Hello there", 0, NULL, REG_GLOBAL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "I said fyhi... there", 0, NULL, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "....hi... ", 0, NULL, REG_GLOBAL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "I said fyhihii there", 0, NULL, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "I said fyhihi there", 0, NULL, REG_GLOBAL), REG_NOMATCH);
regfree(&regex);
}
TEST_CASE(simple_plus)
{
String pattern = "a+";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED | REG_NOSUB), REG_NOERR);
EXPECT_EQ(regexec(&regex, "b", 0, NULL, REG_NOSUB), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a", 0, NULL, REG_NOSUB), REG_NOERR);
EXPECT_EQ(regexec(&regex, "aaaaaabbbbb", 0, NULL, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "aaaaaaaaaaa", 0, NULL, REG_GLOBAL), REG_NOERR);
regfree(&regex);
}
TEST_CASE(simple_questionmark)
{
String pattern = "da?d";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a", 0, NULL, REG_GLOBAL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "daa", 0, NULL, REG_GLOBAL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "ddddd", 0, NULL, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "dd", 0, NULL, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "dad", 0, NULL, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "dada", 0, NULL, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "adadaa", 0, NULL, REG_GLOBAL), REG_NOERR);
regfree(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a", num_matches, matches, REG_GLOBAL), REG_NOMATCH);
EXPECT_EQ(matches[0].rm_cnt, 0);
EXPECT_EQ(regexec(&regex, "daa", num_matches, matches, REG_GLOBAL), REG_NOMATCH);
EXPECT_EQ(matches[0].rm_cnt, 0);
EXPECT_EQ(regexec(&regex, "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(&regex, "dd", num_matches, matches, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(matches[0].rm_cnt, 1);
EXPECT_EQ(regexec(&regex, "dad", num_matches, matches, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(matches[0].rm_cnt, 1);
EXPECT_EQ(regexec(&regex, "dada", num_matches, matches, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(matches[0].rm_cnt, 1);
EXPECT_EQ(regexec(&regex, "adadaa", num_matches, matches, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(matches[0].rm_cnt, 1);
regfree(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, haystack.characters(), num_matches, matches, 0), REG_NOMATCH);
EXPECT_EQ(matches[0].rm_cnt, 0);
EXPECT_EQ(regexec(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED | REG_NEWLINE), REG_NOERR);
EXPECT_EQ(regexec(&regex, 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_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(&regex);
}
TEST_CASE(escaped_char_questionmark)
{
String pattern = "This\\.?And\\.?That";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "ThisAndThat", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "This.And.That", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "This And That", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "This..And..That", 0, NULL, 0), REG_NOMATCH);
regfree(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "#include <regex.h>", num_matches, matches, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(matches[0].rm_cnt, 1);
regfree(&regex);
}
TEST_CASE(char_utf8)
{
String pattern = "😀";
regex_t regex;
static constexpr int num_matches { 5 };
regmatch_t matches[num_matches];
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "Привет, мир! 😀 γειά σου κόσμος 😀 こんにちは世界", num_matches, matches, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(matches[0].rm_cnt, 2);
regfree(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR);
EXPECT_EQ(regexec(&regex, "testhellotest", num_matches, matches, 0), REG_EMPTY_EXPR);
regfree(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), error_code_to_check);
EXPECT_EQ(regexec(&regex, "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(&regex, pattern.characters(), REG_EXTENDED), error_code_to_check);
EXPECT_EQ(regexec(&regex, "test", num_matches, matches, 0), error_code_to_check);
// After circumflex
b.clear();
b.append("^");
b.append(ch);
pattern = b.build();
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), error_code_to_check);
EXPECT_EQ(regexec(&regex, "test", num_matches, matches, 0), error_code_to_check);
// After dollar
b.clear();
b.append("$");
b.append(ch);
pattern = b.build();
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), error_code_to_check);
EXPECT_EQ(regexec(&regex, "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(&regex, pattern.characters(), REG_EXTENDED), error_code_to_check);
EXPECT_EQ(regexec(&regex, "test", num_matches, matches, 0), error_code_to_check);
}
regfree(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR);
EXPECT_EQ(regexec(&regex, "test", num_matches, matches, 0), REG_EMPTY_EXPR);
// Last in ere
pattern = "asdf|";
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR);
EXPECT_EQ(regexec(&regex, "test", num_matches, matches, 0), REG_EMPTY_EXPR);
// After left parens
pattern = "(|asdf)";
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR);
EXPECT_EQ(regexec(&regex, "test", num_matches, matches, 0), REG_EMPTY_EXPR);
// Proceed right parens
pattern = "(asdf)|";
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_EMPTY_EXPR);
EXPECT_EQ(regexec(&regex, "test", num_matches, matches, 0), REG_EMPTY_EXPR);
regfree(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
match_str = "testtest";
EXPECT_EQ(regexec(&regex, 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(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
match_str = "testtest";
EXPECT_EQ(regexec(&regex, 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(&regex, 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(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
match_str = "testasdftest";
EXPECT_EQ(regexec(&regex, 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(&regex, 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(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
match_str = "testabtest";
EXPECT_EQ(regexec(&regex, 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(&regex, 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(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
match_str = "testtest";
EXPECT_EQ(regexec(&regex, 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(&regex, 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(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "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(&regex, "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(&regex, "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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
match_str = "test";
EXPECT_EQ(regexec(&regex, 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(&regex, 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(&regex, 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(&regex, 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(&regex, 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(&regex, 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(&regex, 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(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
match_str = "hello";
EXPECT_EQ(regexec(&regex, match_str, num_matches, matches, 0), REG_NOMATCH);
EXPECT_EQ(matches[0].rm_cnt, 0);
match_str = "hellohellohello";
EXPECT_EQ(regexec(&regex, 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(&regex, 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(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
match_str = "hello";
EXPECT_EQ(regexec(&regex, match_str, num_matches, matches, 0), REG_NOMATCH);
EXPECT_EQ(matches[0].rm_cnt, 0);
match_str = "hellohellohello";
EXPECT_EQ(regexec(&regex, 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(&regex, 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(&regex, 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(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
match_str = "hello";
EXPECT_EQ(regexec(&regex, match_str, num_matches, matches, 0), REG_NOMATCH);
EXPECT_EQ(matches[0].rm_cnt, 0);
match_str = "hellohellohello";
EXPECT_EQ(regexec(&regex, 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(&regex, 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(&regex, 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(&regex, 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(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "cc", num_matches, matches, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "ccc", num_matches, matches, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "cccccccccccccccccccccccccccccc", num_matches, matches, 0), REG_NOERR);
EXPECT_EQ(matches[0].rm_cnt, 1);
EXPECT_EQ(regexec(&regex, "ccccccccccccccccccccccccccccccc", num_matches, matches, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "ccccccccccccccccccccccccccccccc", num_matches, matches, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "cccccccccccccccccccccccccccccccc", num_matches, matches, 0), REG_NOMATCH);
regfree(&regex);
}
TEST_CASE(simple_bracket_chars)
{
String pattern = "[abc]";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "b", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "c", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "d", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "e", 0, NULL, 0), REG_NOMATCH);
}
TEST_CASE(simple_bracket_chars_inverse)
{
String pattern = "[^abc]";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "b", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "c", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "d", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "e", 0, NULL, 0), REG_NOERR);
}
TEST_CASE(simple_bracket_chars_range)
{
String pattern = "[a-d]";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "b", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "c", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "d", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "e", 0, NULL, 0), REG_NOMATCH);
}
TEST_CASE(simple_bracket_chars_range_inverse)
{
String pattern = "[^a-df-z]";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "b", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "c", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "d", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "e", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "k", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "fb9b62a2-1579-4e3a-afba-76239ccb6583", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "fb9b62a2", 0, NULL, 0), REG_NOMATCH);
regfree(&regex);
}
TEST_CASE(simple_bracket_character_class_inverse)
{
String pattern = "[^[:digit:]]";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "1", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "2", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "3", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "d", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "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(&regex, pattern.characters(), REG_EXTENDED), REG_NOERR);
EXPECT_EQ(regexec(&regex, "emanuel.sprung@gmail.com", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "kling@serenityos.org", 0, NULL, 0), REG_NOERR);
regfree(&regex);
}
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(&regex, pattern.characters(), REG_EXTENDED), REG_EBRACK);
EXPECT_EQ(regexec(&regex, "asdf@asdf.com", 0, NULL, 0), REG_EBRACK);
char buf[1024];
size_t buflen = 1024;
auto len = regerror(0, &regex, 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(&regex);
}
TEST_CASE(simple_ignorecase)
{
String pattern = "^hello friends";
regex_t regex;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR);
EXPECT_EQ(regexec(&regex, "Hello Friends", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hello Friends", 0, NULL, 0), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hello Friends!", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello Friends!", 0, NULL, REG_GLOBAL), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hell Friends", 0, NULL, 0), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hell Friends", 0, NULL, REG_GLOBAL), REG_NOMATCH);
regfree(&regex);
}
TEST_CASE(simple_notbol_noteol)
{
String pattern = "^hello friends$";
String pattern2 = "hello friends";
regex_t regex, regex2;
EXPECT_EQ(regcomp(&regex, pattern.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR);
EXPECT_EQ(regcomp(&regex2, pattern2.characters(), REG_EXTENDED | REG_NOSUB | REG_ICASE), REG_NOERR);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends", 0, NULL, REG_NOTBOL | REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends", 0, NULL, REG_NOTBOL | REG_SEARCH), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_SEARCH), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends b", 0, NULL, REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "hello friends b", 0, NULL, REG_NOTEOL | REG_SEARCH), REG_NOERR);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTEOL | REG_SEARCH), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex, "a hello friends b", 0, NULL, REG_NOTBOL | REG_NOTEOL | REG_SEARCH), REG_NOMATCH);
EXPECT_EQ(regexec(&regex2, "hello friends", 0, NULL, REG_NOTBOL), REG_NOMATCH);
EXPECT_EQ(regexec(&regex2, "hello friends", 0, NULL, REG_NOTEOL), REG_NOMATCH);
regfree(&regex);
}