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:
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -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]")
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user