Merge branch 'regex-tests'

Fix regex-related tests to actually run as part of the test suite again.

See https://github.com/wxWidgets/wxWidgets/pull/2279
This commit is contained in:
Vadim Zeitlin
2021-03-14 13:06:20 +01:00
4 changed files with 709 additions and 1460 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@
# Notes: # Notes:
# See './regex.pl -h' for usage # See './regex.pl -h' for usage
# #
# Output at the moment is C++ using the cppunit testing framework. The # Output at the moment is C++ using the CATCH testing framework. The
# language/framework specifics are separated, with the following 5 # language/framework specifics are separated, with the following 5
# subs as an interface: 'begin_output', 'begin_section', 'write_test', # subs as an interface: 'begin_output', 'begin_section', 'write_test',
# 'end_section' and 'end_output'. So for a different language/framework, # 'end_section' and 'end_output'. So for a different language/framework,
@@ -87,15 +87,10 @@ $from$instructions */
EOT EOT
} }
my @classes;
# start a new section (C++ interface) # start a new section (C++ interface)
# #
sub begin_section { sub begin_section {
my ($id, $title) = @_; my ($id, $title) = @_;
my $class = "regextest_$id";
$class =~ s/\W/_/g;
push @classes, [$id, $class];
print <<EOT; print <<EOT;
@@ -103,17 +98,8 @@ sub begin_section {
* $id $title * $id $title
*/ */
class $class : public RegExTestSuite TEST_CASE("regex::$title", "[regex][regex_$id][builtin]")
{ {
public:
$class() : RegExTestSuite("regex.$id") { }
static Test *suite();
};
Test *$class\::suite()
{
RegExTestSuite *suite = new $class;
EOT EOT
} }
@@ -122,21 +108,15 @@ EOT
sub write_test { sub write_test {
my @args = @_; my @args = @_;
$_ = quotecxx for @args; $_ = quotecxx for @args;
print " suite->add(" . (join ', ', @args) . ", NULL);\n"; print " CheckRE(" . (join ', ', @args) . ", NULL);\n";
} }
# end a section (C++ interface) # end a section (C++ interface)
# #
sub end_section { sub end_section {
my ($id, $class) = @{$classes[$#classes]};
print <<EOT; print <<EOT;
return suite;
} }
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION($class, "regex.$id");
EOT EOT
} }
@@ -144,32 +124,9 @@ EOT
# #
sub end_output { sub end_output {
print <<EOT; print <<EOT;
/* /*
* A suite containing all the above suites * End of generated test suite.
*/ */
class regextest : public TestSuite
{
public:
regextest() : TestSuite("regex") { }
static Test *suite();
};
Test *regextest::suite()
{
TestSuite *suite = new regextest;
EOT
print " suite->addTest(".$_->[1]."::suite());\n" for @classes;
print <<EOT;
return suite;
}
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(regextest, "regex");
CPPUNIT_TEST_SUITE_REGISTRATION(regextest);
EOT EOT
} }

View File

@@ -49,22 +49,16 @@
#include <string> #include <string>
#include <vector> #include <vector>
using CppUnit::Test;
using CppUnit::TestCase;
using CppUnit::TestSuite;
using std::string; using std::string;
using std::vector; using std::vector;
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// The test case - an instance represents a single test // The test case - an instance represents a single test
class RegExTestCase : public TestCase class RegExTestCase
{ {
public: public:
// constructor - create a single testcase
RegExTestCase( RegExTestCase(
const string& name,
const char *mode, const char *mode,
const char *id, const char *id,
const char *flags, const char *flags,
@@ -72,22 +66,14 @@ public:
const char *data, const char *data,
const vector<const char *>& expected); const vector<const char *>& expected);
protected:
// run this testcase
void runTest() wxOVERRIDE;
private: private:
void runTest();
// workers // workers
wxString Conv(const char *str); wxString Conv(const char *str);
void parseFlags(const wxString& flags); bool parseFlags(const wxString& flags);
void doTest(int flavor); void doTest(int flavor);
static wxString quote(const wxString& arg); static wxString quote(const wxString& arg);
const wxChar *convError() const { return wxT("<cannot convert>"); }
// assertions - adds some information about the test that failed
void fail(const wxString& msg) const;
void failIf(bool condition, const wxString& msg) const
{ if (condition) fail(msg); }
// mode, id, flags, pattern, test data, expected results... // mode, id, flags, pattern, test data, expected results...
int m_mode; int m_mode;
@@ -108,7 +94,6 @@ private:
// constructor - throws Exception on failure // constructor - throws Exception on failure
// //
RegExTestCase::RegExTestCase( RegExTestCase::RegExTestCase(
const string& name,
const char *mode, const char *mode,
const char *id, const char *id,
const char *flags, const char *flags,
@@ -116,7 +101,6 @@ RegExTestCase::RegExTestCase(
const char *data, const char *data,
const vector<const char *>& expected) const vector<const char *>& expected)
: :
TestCase(name),
m_mode(mode[0]), m_mode(mode[0]),
m_id(Conv(id)), m_id(Conv(id)),
m_flags(Conv(flags)), m_flags(Conv(flags)),
@@ -128,22 +112,13 @@ RegExTestCase::RegExTestCase(
m_extended(false), m_extended(false),
m_advanced(false) m_advanced(false)
{ {
bool badconv = m_pattern == convError() || m_data == convError();
vector<const char *>::const_iterator it; vector<const char *>::const_iterator it;
for (it = expected.begin(); it != expected.end(); ++it) { for (it = expected.begin(); it != expected.end(); ++it) {
m_expected.push_back(Conv(*it)); m_expected.push_back(Conv(*it));
badconv = badconv || *m_expected.rbegin() == convError();
} }
failIf(badconv, wxT("cannot convert to default character encoding")); runTest();
// the flags need further parsing...
parseFlags(m_flags);
#ifndef wxHAS_REGEX_ADVANCED
failIf(!m_basic && !m_extended, wxT("advanced regexs not available"));
#endif
} }
int wxWcscmp(const wchar_t* s1, const wchar_t* s2) int wxWcscmp(const wchar_t* s1, const wchar_t* s2)
@@ -165,14 +140,16 @@ wxString RegExTestCase::Conv(const char *str)
const wxWC2WXbuf buf = wxConvCurrent->cWC2WX(wstr); const wxWC2WXbuf buf = wxConvCurrent->cWC2WX(wstr);
if (!buf || wxWcscmp(wxConvCurrent->cWX2WC(buf), wstr) != 0) if (!buf || wxWcscmp(wxConvCurrent->cWX2WC(buf), wstr) != 0)
return convError(); {
FAIL( "Converting string \"" << str << "\" failed" );
}
return buf; return buf;
} }
// Parse flags // Parse flags
// //
void RegExTestCase::parseFlags(const wxString& flags) bool RegExTestCase::parseFlags(const wxString& flags)
{ {
for ( wxString::const_iterator p = flags.begin(); p != flags.end(); ++p ) for ( wxString::const_iterator p = flags.begin(); p != flags.end(); ++p )
{ {
@@ -205,16 +182,39 @@ void RegExTestCase::parseFlags(const wxString& flags)
// anything else we must skip the test // anything else we must skip the test
default: default:
fail(wxString::Format( return false;
wxT("requires unsupported flag '%c'"), *p));
} }
} }
return true;
} }
// Try test for all flavours of expression specified // Try test for all flavours of expression specified
// //
void RegExTestCase::runTest() void RegExTestCase::runTest()
{ {
// the flags need further parsing...
if (!parseFlags(m_flags)) {
// we just have to skip the unsupported flags now
return;
}
// Provide more information about the test case if it fails.
wxString str;
wxArrayString::const_iterator it;
str << (wxChar)m_mode << wxT(" ") << m_id << wxT(" ") << m_flags << wxT(" ")
<< quote(m_pattern) << wxT(" ") << quote(m_data);
for (it = m_expected.begin(); it != m_expected.end(); ++it)
str << wxT(" ") << quote(*it);
if (str.length() > 77)
str = str.substr(0, 74) + wxT("...");
INFO( str );
if (m_basic) if (m_basic)
doTest(wxRE_BASIC); doTest(wxRE_BASIC);
if (m_extended) if (m_extended)
@@ -233,38 +233,39 @@ void RegExTestCase::doTest(int flavor)
// 'e' - test that the pattern fails to compile // 'e' - test that the pattern fails to compile
if (m_mode == 'e') { if (m_mode == 'e') {
failIf(re.IsValid(), wxT("compile succeeded (should fail)")); CHECK( !re.IsValid() );
return; } else {
CHECK( re.IsValid() );
} }
failIf(!re.IsValid(), wxT("compile failed"));
if (!re.IsValid())
return;
bool matches = re.Matches(m_data, m_matchFlags); bool matches = re.Matches(m_data, m_matchFlags);
// 'f' or 'p' - test that the pattern does not match // 'f' or 'p' - test that the pattern does not match
if (m_mode == 'f' || m_mode == 'p') { if (m_mode == 'f' || m_mode == 'p') {
failIf(matches, wxT("match succeeded (should fail)")); CHECK( !matches );
return; } else {
// otherwise 'm' or 'i' - test the pattern does match
CHECK( matches );
} }
// otherwise 'm' or 'i' - test the pattern does match if (!matches)
failIf(!matches, wxT("match failed")); return;
if (m_compileFlags & wxRE_NOSUB) if (m_compileFlags & wxRE_NOSUB)
return; return;
// check wxRegEx has correctly counted the number of subexpressions // check wxRegEx has correctly counted the number of subexpressions
wxString msg; CHECK( m_expected.size() == re.GetMatchCount() );
msg << wxT("GetMatchCount() == ") << re.GetMatchCount()
<< wxT(", expected ") << m_expected.size();
failIf(m_expected.size() != re.GetMatchCount(), msg);
for (size_t i = 0; i < m_expected.size(); i++) { for (size_t i = 0; i < m_expected.size(); i++) {
wxString result; wxString result;
size_t start, len; size_t start, len;
msg.clear(); INFO( "Match " << i );
msg << wxT("wxRegEx::GetMatch failed for match ") << i; CHECK( re.GetMatch(&start, &len, i) );
failIf(!re.GetMatch(&start, &len, i), msg);
// m - check the match returns the strings given // m - check the match returns the strings given
if (m_mode == 'm') if (m_mode == 'm')
@@ -286,35 +287,10 @@ void RegExTestCase::doTest(int flavor)
result << start << wxT(" -1"); result << start << wxT(" -1");
} }
msg.clear(); CHECK( result == m_expected[i] );
msg << wxT("match(") << i << wxT(") == ") << quote(result)
<< wxT(", expected == ") << quote(m_expected[i]);
failIf(result != m_expected[i], msg);
} }
} }
// assertion - adds some information about the test that failed
//
void RegExTestCase::fail(const wxString& msg) const
{
wxString str;
wxArrayString::const_iterator it;
str << (wxChar)m_mode << wxT(" ") << m_id << wxT(" ") << m_flags << wxT(" ")
<< quote(m_pattern) << wxT(" ") << quote(m_data);
for (it = m_expected.begin(); it != m_expected.end(); ++it)
str << wxT(" ") << quote(*it);
if (str.length() > 77)
str = str.substr(0, 74) + wxT("...");
str << wxT("\n ") << msg;
// no lossy convs so using utf8
CPPUNIT_FAIL(string(str.mb_str(wxConvUTF8)));
}
// quote a string so that it can be displayed (static) // quote a string so that it can be displayed (static)
// //
wxString RegExTestCase::quote(const wxString& arg) wxString RegExTestCase::quote(const wxString& arg)
@@ -339,30 +315,17 @@ wxString RegExTestCase::quote(const wxString& arg)
str : wxT("\"") + str + wxT("\""); str : wxT("\"") + str + wxT("\"");
} }
// The helper function used by the tests in auto-generated regex.inc.
/////////////////////////////////////////////////////////////////////////////// static void
// Test suite CheckRE(
const char *mode,
class RegExTestSuite : public TestSuite const char *id,
const char *flags,
const char *pattern,
const char *data,
const char *expected,
...)
{ {
public:
RegExTestSuite(string name) : TestSuite(name) { }
void add(const char *mode, const char *id, const char *flags,
const char *pattern, const char *data, const char *expected, ...);
};
// Add a testcase to the suite
//
void RegExTestSuite::add(
const char *mode,
const char *id,
const char *flags,
const char *pattern,
const char *data,
const char *expected, ...)
{
string name = getName() + "." + id;
vector<const char *> expected_results; vector<const char *> expected_results;
va_list ap; va_list ap;
@@ -371,8 +334,7 @@ void RegExTestSuite::add(
va_end(ap); va_end(ap);
addTest(new RegExTestCase( RegExTestCase(mode, id, flags, pattern, data, expected_results);
name, mode, id, flags, pattern, data, expected_results));
} }

View File

@@ -18,287 +18,11 @@
#include "wx/tokenzr.h" #include "wx/tokenzr.h"
#include <string> #include <string>
using CppUnit::Test;
using CppUnit::TestCase;
using CppUnit::TestSuite;
using std::string; using std::string;
///////////////////////////////////////////////////////////////////////////////
// Compile Test
class RegExCompileTestCase : public TestCase
{
public:
RegExCompileTestCase(const char *name, const wxString& pattern,
bool correct, int flags)
: TestCase(name),
m_pattern(pattern),
m_correct(correct),
m_flags(flags)
{ }
protected:
void runTest() wxOVERRIDE;
private:
wxString m_pattern;
bool m_correct;
int m_flags;
};
void RegExCompileTestCase::runTest()
{
wxRegEx re;
bool ok = re.Compile(m_pattern, m_flags);
if (m_correct)
CPPUNIT_ASSERT_MESSAGE("compile failed", ok);
else
CPPUNIT_ASSERT_MESSAGE("compile succeeded (should fail)", !ok);
}
///////////////////////////////////////////////////////////////////////////////
// Match Test
class RegExMatchTestCase : public TestCase
{
public:
RegExMatchTestCase(const char *name, const wxString& pattern,
const wxString& text, const char *expected,
int flags)
: TestCase(name),
m_pattern(pattern),
m_text(text),
m_expected(expected),
m_flags(flags)
{ }
protected:
void runTest() wxOVERRIDE;
private:
wxString m_pattern;
wxString m_text;
const char *m_expected;
int m_flags;
};
void RegExMatchTestCase::runTest()
{
int compileFlags = m_flags & ~(wxRE_NOTBOL | wxRE_NOTEOL);
int matchFlags = m_flags & (wxRE_NOTBOL | wxRE_NOTEOL);
wxRegEx re(m_pattern, compileFlags);
CPPUNIT_ASSERT_MESSAGE("compile failed", re.IsValid());
bool ok = re.Matches(m_text, matchFlags);
if (m_expected) {
CPPUNIT_ASSERT_MESSAGE("match failed", ok);
wxStringTokenizer tkz(wxString(m_expected, *wxConvCurrent),
wxT("\t"), wxTOKEN_RET_EMPTY);
size_t i;
for (i = 0; i < re.GetMatchCount() && tkz.HasMoreTokens(); i++) {
wxString expected = tkz.GetNextToken();
wxString result = re.GetMatch(m_text, i);
wxString msgstr;
msgstr.Printf(wxT("\\%d == '%s' (expected '%s')"),
(int)i, result.c_str(), expected.c_str());
CPPUNIT_ASSERT_MESSAGE((const char*)msgstr.mb_str(),
result == expected);
}
if ((m_flags & wxRE_NOSUB) == 0)
CPPUNIT_ASSERT(re.GetMatchCount() == i);
}
else {
CPPUNIT_ASSERT_MESSAGE("match succeeded (should fail)", !ok);
}
}
///////////////////////////////////////////////////////////////////////////////
// Replacement Test
class RegExReplaceTestCase : public TestCase
{
public:
RegExReplaceTestCase(const char *name, const wxString& pattern,
const wxString& text, const wxString& repl,
const wxString& expected, size_t count, int flags)
: TestCase(name),
m_pattern(pattern),
m_text(text),
m_repl(repl),
m_expected(expected),
m_count(count),
m_flags(flags)
{ }
protected:
void runTest() wxOVERRIDE;
private:
wxString m_pattern;
wxString m_text;
wxString m_repl;
wxString m_expected;
size_t m_count;
int m_flags;
};
void RegExReplaceTestCase::runTest()
{
wxRegEx re(m_pattern, m_flags);
wxString text(m_text);
size_t nRepl = re.Replace(&text, m_repl);
wxString msgstr;
msgstr.Printf(wxT("returns '%s' (expected '%s')"), text.c_str(), m_expected.c_str());
CPPUNIT_ASSERT_MESSAGE((const char*)msgstr.mb_str(), text == m_expected);
msgstr.Printf(wxT("matches %d times (expected %d)"), (int)nRepl, (int)m_count);
CPPUNIT_ASSERT_MESSAGE((const char*)msgstr.mb_str(), nRepl == m_count);
}
///////////////////////////////////////////////////////////////////////////////
// The suite
class wxRegExTestSuite : public TestSuite
{
public:
wxRegExTestSuite() : TestSuite("wxRegExTestSuite") { }
static Test *suite();
private:
void add(const char *pattern, bool correct, int flags = wxRE_DEFAULT);
void add(const char *pattern, const char *text,
const char *expected = NULL, int flags = wxRE_DEFAULT);
void add(const char *pattern, const char *text, const char *replacement,
const char *expected, size_t count, int flags = wxRE_DEFAULT);
static wxString FlagStr(int flags);
static wxString Conv(const char *str) { return wxString(str, *wxConvCurrent); }
};
// Build the suite (static)
//
Test *wxRegExTestSuite::suite()
{
wxRegExTestSuite *suite = new wxRegExTestSuite;
// Compile tests
// pattern, expected result
suite->add("foo", true);
suite->add("foo(", false);
suite->add("foo(bar", false);
suite->add("foo(bar)", true);
suite->add("foo[", false);
suite->add("foo[bar", false);
suite->add("foo[bar]", true);
suite->add("foo{1", false);
suite->add("foo{1}", true);
suite->add("foo{1,2}", true);
suite->add("foo*", true);
suite->add("foo+", true);
suite->add("foo?", true);
// Match tests
// pattern, text, expected results (match, followed by submatches
// tab separated, or NULL for no match expected)
suite->add("foo", "bar");
suite->add("foo", "foobar", "foo");
suite->add("^foo", "foobar", "foo");
suite->add("^foo", "barfoo");
suite->add("bar$", "barbar", "bar");
suite->add("bar$", "barbar ");
suite->add("OoBa", "FoObAr", "oObA", wxRE_ICASE);
suite->add("^[A-Z].*$", "AA\nbb\nCC", "AA\nbb\nCC");
suite->add("^[A-Z].*$", "AA\nbb\nCC", "AA", wxRE_NEWLINE);
suite->add("^[a-z].*$", "AA\nbb\nCC", "bb", wxRE_NEWLINE);
suite->add("^[A-Z].*$", "AA\nbb\nCC", "CC", wxRE_NEWLINE | wxRE_NOTBOL);
suite->add("^[A-Z].*$", "AA\nbb\nCC", NULL, wxRE_NEWLINE | wxRE_NOTBOL | wxRE_NOTEOL);
suite->add("([[:alpha:]]+) ([[:alpha:]]+) ([[:digit:]]+).* ([[:digit:]]+)$",
"Fri Jul 13 18:37:52 CEST 2001",
"Fri Jul 13 18:37:52 CEST 2001\tFri\tJul\t13\t2001");
// Replace tests
// pattern, text, replacement, expected result and number of matches
const char *patn = "([a-z]+)[^0-9]*([0-9]+)";
suite->add(patn, "foo123", "bar", "bar", 1);
suite->add(patn, "foo123", "\\2\\1", "123foo", 1);
suite->add(patn, "foo_123", "\\2\\1", "123foo", 1);
suite->add(patn, "123foo", "bar", "123foo", 0);
suite->add(patn, "123foo456foo", "&&", "123foo456foo456foo", 1);
suite->add(patn, "123foo456foo", "\\0\\0", "123foo456foo456foo", 1);
suite->add(patn, "foo123foo123", "bar", "barbar", 2);
suite->add(patn, "foo123_foo456_foo789", "bar", "bar_bar_bar", 3);
return suite;
}
// Add a compile test
//
void wxRegExTestSuite::add(
const char *pattern,
bool correct,
int flags /*=wxRE_DEFAULT*/)
{
addTest(new RegExCompileTestCase(
(wxT("/") + Conv(pattern) + wxT("/") + FlagStr(flags)).mb_str(),
Conv(pattern), correct, flags));
}
// Add a match test
//
void wxRegExTestSuite::add(
const char *pattern,
const char *text,
const char *expected /*=NULL*/,
int flags /*=wxRE_DEFAULT*/)
{
wxString name;
name << wxT("'") << Conv(text) << wxT("' =~ /") << Conv(pattern) << wxT("/")
<< FlagStr(flags);
name.Replace(wxT("\n"), wxT("\\n"));
addTest(new RegExMatchTestCase(name.mb_str(), Conv(pattern),
Conv(text), expected, flags));
}
// Add a replace test
//
void wxRegExTestSuite::add(
const char *pattern,
const char *text,
const char *replacement,
const char *expected,
size_t count,
int flags /*=wxRE_DEFAULT*/)
{
wxString name;
name << wxT("'") << Conv(text) << wxT("' =~ s/") << Conv(pattern) << wxT("/")
<< Conv(replacement) << wxT("/g") << FlagStr(flags);
name.Replace(wxT("\n"), wxT("\\n"));
addTest(new RegExReplaceTestCase(
name.mb_str(), Conv(pattern), Conv(text),
Conv(replacement), Conv(expected), count, flags));
}
// Display string for the flags // Display string for the flags
// //
wxString wxRegExTestSuite::FlagStr(int flags) static wxString FlagStr(int flags)
{ {
wxString str; wxString str;
@@ -324,11 +48,112 @@ wxString wxRegExTestSuite::FlagStr(int flags)
return wxT(" (") + str.Mid(3) + wxT(")"); return wxT(" (") + str.Mid(3) + wxT(")");
} }
// register in the unnamed registry so that these tests are run by default TEST_CASE("wxRegEx::Compile", "[regex][compile]")
CPPUNIT_TEST_SUITE_REGISTRATION(wxRegExTestSuite); {
wxRegEx re;
// also include in its own registry so that these tests can be run alone CHECK ( re.Compile("foo") );
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(wxRegExTestSuite, "wxRegExTestSuite"); CHECK_FALSE( re.Compile("foo(") );
CHECK_FALSE( re.Compile("foo(bar") );
CHECK ( re.Compile("foo(bar)") );
CHECK_FALSE( re.Compile("foo[") );
CHECK_FALSE( re.Compile("foo[bar") );
CHECK ( re.Compile("foo[bar]") );
CHECK_FALSE( re.Compile("foo{1") );
CHECK ( re.Compile("foo{1}") );
CHECK ( re.Compile("foo{1,2}") );
CHECK ( re.Compile("foo*") );
CHECK ( re.Compile("foo+") );
CHECK ( re.Compile("foo?") );
}
static void
CheckMatch(const char* pattern,
const char* text,
const char* expected = NULL,
int flags = wxRE_DEFAULT)
{
int compileFlags = flags & ~(wxRE_NOTBOL | wxRE_NOTEOL);
int matchFlags = flags & (wxRE_NOTBOL | wxRE_NOTEOL);
INFO( "Pattern: " << pattern << FlagStr(flags) << ", match: " << text );
wxRegEx re(pattern, compileFlags);
REQUIRE( re.IsValid() );
bool ok = re.Matches(text, matchFlags);
if (expected) {
REQUIRE( ok );
wxStringTokenizer tkz(wxString(expected, *wxConvCurrent),
wxT("\t"), wxTOKEN_RET_EMPTY);
size_t i;
for (i = 0; i < re.GetMatchCount() && tkz.HasMoreTokens(); i++) {
INFO( "Match #" << i );
CHECK( re.GetMatch(text, i) == tkz.GetNextToken() );
}
if ((flags & wxRE_NOSUB) == 0)
CHECK(re.GetMatchCount() == i);
}
else {
CHECK( !ok );
}
}
TEST_CASE("wxRegEx::Match", "[regex][match]")
{
// Match tests
// pattern, text, expected results (match, followed by submatches
// tab separated, or NULL for no match expected)
CheckMatch("foo", "bar");
CheckMatch("foo", "foobar", "foo");
CheckMatch("^foo", "foobar", "foo");
CheckMatch("^foo", "barfoo");
CheckMatch("bar$", "barbar", "bar");
CheckMatch("bar$", "barbar ");
CheckMatch("OoBa", "FoObAr", "oObA", wxRE_ICASE);
CheckMatch("^[A-Z].*$", "AA\nbb\nCC", "AA\nbb\nCC");
CheckMatch("^[A-Z].*$", "AA\nbb\nCC", "AA", wxRE_NEWLINE);
CheckMatch("^[a-z].*$", "AA\nbb\nCC", "bb", wxRE_NEWLINE);
CheckMatch("^[A-Z].*$", "AA\nbb\nCC", "CC", wxRE_NEWLINE | wxRE_NOTBOL);
CheckMatch("^[A-Z].*$", "AA\nbb\nCC", NULL, wxRE_NEWLINE | wxRE_NOTBOL | wxRE_NOTEOL);
CheckMatch("([[:alpha:]]+) ([[:alpha:]]+) ([[:digit:]]+).* ([[:digit:]]+)$",
"Fri Jul 13 18:37:52 CEST 2001",
"Fri Jul 13 18:37:52 CEST 2001\tFri\tJul\t13\t2001");
}
static void
CheckReplace(const char* pattern,
const char* original,
const char* replacement,
const char* expected,
size_t numMatches)
{
wxRegEx re(pattern);
wxString text(original);
CHECK( re.Replace(&text, replacement) == numMatches );
CHECK( text == expected );
}
TEST_CASE("wxRegEx::Replace", "[regex][replace]")
{
// Replace tests
// pattern, text, replacement, expected result and number of matches
const char *patn = "([a-z]+)[^0-9]*([0-9]+)";
CheckReplace(patn, "foo123", "bar", "bar", 1);
CheckReplace(patn, "foo123", "\\2\\1", "123foo", 1);
CheckReplace(patn, "foo_123", "\\2\\1", "123foo", 1);
CheckReplace(patn, "123foo", "bar", "123foo", 0);
CheckReplace(patn, "123foo456foo", "&&", "123foo456foo456foo", 1);
CheckReplace(patn, "123foo456foo", "\\0\\0", "123foo456foo456foo", 1);
CheckReplace(patn, "foo123foo123", "bar", "barbar", 2);
CheckReplace(patn, "foo123_foo456_foo789", "bar", "bar_bar_bar", 3);
}
TEST_CASE("wxRegEx::QuoteMeta", "[regex][meta]") TEST_CASE("wxRegEx::QuoteMeta", "[regex][meta]")
{ {