]>
git.saurik.com Git - wxWidgets.git/blob - tests/regex/regextest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/regex/regex.cpp
3 // Purpose: Test the built-in regex lib and wxRegEx
4 // Author: Mike Wetherell
5 // Copyright: (c) 2004 Mike Wetherell
6 // Licence: wxWindows licence
7 ///////////////////////////////////////////////////////////////////////////////
12 // To run just one section, say wx_1, do this:
15 // To run all the regex tests:
18 // Some tests must be skipped since they use features which we do not make
19 // available through wxRegEx. To see the list of tests that have been skipped
20 // turn on verbose logging, e.g.:
21 // test --verbose regex
23 // The tests here are for the builtin library, tests for wxRegEx in general
24 // should go in wxregex.cpp
26 // The tests are generated from Henry Spencer's reg.test, additional test
27 // can be added in wxreg.test. These test files are then turned into a C++
28 // include file 'regex.inc' (included below) using a script 'regex.pl'.
31 // For compilers that support precompilation, includes "wx/wx.h".
40 // for all others, include the necessary headers
46 // many of the tests are specific to the builtin regex lib, so only attempts
47 // to do them when using the builtin regex lib.
49 #ifdef wxHAS_REGEX_ADVANCED
56 using CppUnit::TestCase
;
57 using CppUnit::TestSuite
;
58 using CppUnit::Exception
;
63 ///////////////////////////////////////////////////////////////////////////////
64 // The test case - an instance represents a single test
66 class RegExTestCase
: public TestCase
69 // constructor - create a single testcase
77 const vector
<const char *>& expected
);
85 wxString
Conv(const char *str
);
86 void parseFlags(const wxString
& flags
);
87 void doTest(int flavor
);
88 static wxString
quote(const wxString
& arg
);
89 const wxChar
*convError() const { return wxT("<cannot convert>"); }
91 // assertions - adds some information about the test that failed
92 void fail(const wxString
& msg
) const;
93 void failIf(bool condition
, const wxString
& msg
) const
94 { if (condition
) fail(msg
); }
96 // mode, id, flags, pattern, test data, expected results...
102 wxArrayString m_expected
;
112 // constructor - throws Exception on failure
114 RegExTestCase::RegExTestCase(
121 const vector
<const char *>& expected
)
126 m_flags(Conv(flags
)),
127 m_pattern(Conv(pattern
)),
135 bool badconv
= m_pattern
== convError() || m_data
== convError();
136 //RN: Removing the std:: here will break MSVC6 compilation
137 std::vector
<const char *>::const_iterator it
;
139 for (it
= expected
.begin(); it
!= expected
.end(); ++it
) {
140 m_expected
.push_back(Conv(*it
));
141 badconv
= badconv
|| *m_expected
.rbegin() == convError();
144 failIf(badconv
, wxT("cannot convert to default character encoding"));
146 // the flags need further parsing...
149 #ifndef wxHAS_REGEX_ADVANCED
150 failIf(!m_basic
&& !m_extended
, wxT("advanced regexs not available"));
154 int wxWcscmp(const wchar_t* s1
, const wchar_t* s2
)
156 size_t nLen1
= wxWcslen(s1
);
157 size_t nLen2
= wxWcslen(s2
);
160 return nLen1
- nLen2
;
162 return memcmp(s1
, s2
, nLen1
*sizeof(wchar_t));
165 // convert a string from UTF8 to the internal encoding
167 wxString
RegExTestCase::Conv(const char *str
)
169 const wxWCharBuffer wstr
= wxConvUTF8
.cMB2WC(str
);
170 const wxWC2WXbuf buf
= wxConvCurrent
->cWC2WX(wstr
);
172 if (!buf
|| wxWcscmp(wxConvCurrent
->cWX2WC(buf
), wstr
) != 0)
180 void RegExTestCase::parseFlags(const wxString
& flags
)
182 for ( wxString::const_iterator p
= flags
.begin(); p
!= flags
.end(); ++p
)
184 switch ( (*p
).GetValue() ) {
188 // we don't fully support these flags, but they don't stop us
189 // checking for success of failure of the match, so treat as noop
190 case 'A': case 'B': case 'E': case 'H':
191 case 'I': case 'L': case 'M': case 'N':
192 case 'P': case 'Q': case 'R': case 'S':
193 case 'T': case 'U': case '%':
197 case '^': m_matchFlags
|= wxRE_NOTBOL
; break;
198 case '$': m_matchFlags
|= wxRE_NOTEOL
; break;
203 case '&': m_advanced
= m_basic
= true; break;
204 case 'b': m_basic
= true; break;
205 case 'e': m_extended
= true; break;
206 case 'i': m_compileFlags
|= wxRE_ICASE
; break;
207 case 'o': m_compileFlags
|= wxRE_NOSUB
; break;
208 case 'n': m_compileFlags
|= wxRE_NEWLINE
; break;
209 case 't': if (strchr("ep", m_mode
)) break; // else fall through...
211 // anything else we must skip the test
213 fail(wxString::Format(
214 wxT("requires unsupported flag '%c'"), *p
));
219 // Try test for all flavours of expression specified
221 void RegExTestCase::runTest()
226 doTest(wxRE_EXTENDED
);
227 #ifdef wxHAS_REGEX_ADVANCED
228 if (m_advanced
|| (!m_basic
&& !m_extended
))
229 doTest(wxRE_ADVANCED
);
233 // Try the test for a single flavour of expression
235 void RegExTestCase::doTest(int flavor
)
237 wxRegEx
re(m_pattern
, m_compileFlags
| flavor
);
239 // 'e' - test that the pattern fails to compile
241 failIf(re
.IsValid(), wxT("compile succeeded (should fail)"));
244 failIf(!re
.IsValid(), wxT("compile failed"));
246 bool matches
= re
.Matches(m_data
, m_matchFlags
);
248 // 'f' or 'p' - test that the pattern does not match
249 if (m_mode
== 'f' || m_mode
== 'p') {
250 failIf(matches
, wxT("match succeeded (should fail)"));
254 // otherwise 'm' or 'i' - test the pattern does match
255 failIf(!matches
, wxT("match failed"));
257 if (m_compileFlags
& wxRE_NOSUB
)
260 // check wxRegEx has correctly counted the number of subexpressions
262 msg
<< wxT("GetMatchCount() == ") << re
.GetMatchCount()
263 << wxT(", expected ") << m_expected
.size();
264 failIf(m_expected
.size() != re
.GetMatchCount(), msg
);
266 for (size_t i
= 0; i
< m_expected
.size(); i
++) {
271 msg
<< wxT("wxRegEx::GetMatch failed for match ") << i
;
272 failIf(!re
.GetMatch(&start
, &len
, i
), msg
);
274 // m - check the match returns the strings given
278 result
= m_data
.substr(start
, len
);
283 // i - check the match returns the offsets given
284 else if (m_mode
== 'i')
287 result
= wxT("-1 -1");
288 else if (start
+ len
> 0)
289 result
<< start
<< wxT(" ") << start
+ len
- 1;
291 result
<< start
<< wxT(" -1");
295 msg
<< wxT("match(") << i
<< wxT(") == ") << quote(result
)
296 << wxT(", expected == ") << quote(m_expected
[i
]);
297 failIf(result
!= m_expected
[i
], msg
);
301 // assertion - adds some information about the test that failed
303 void RegExTestCase::fail(const wxString
& msg
) const
306 wxArrayString::const_iterator it
;
308 str
<< (wxChar
)m_mode
<< wxT(" ") << m_id
<< wxT(" ") << m_flags
<< wxT(" ")
309 << quote(m_pattern
) << wxT(" ") << quote(m_data
);
311 for (it
= m_expected
.begin(); it
!= m_expected
.end(); ++it
)
312 str
<< wxT(" ") << quote(*it
);
314 if (str
.length() > 77)
315 str
= str
.substr(0, 74) + wxT("...");
317 str
<< wxT("\n ") << msg
;
319 // no lossy convs so using utf8
320 CPPUNIT_FAIL(string(str
.mb_str(wxConvUTF8
)));
323 // quote a string so that it can be displayed (static)
325 wxString
RegExTestCase::quote(const wxString
& arg
)
327 const wxChar
*needEscape
= wxT("\a\b\t\n\v\f\r\"\\");
328 const wxChar
*escapes
= wxT("abtnvfr\"\\");
331 for (size_t i
= 0; i
< arg
.length(); i
++) {
332 wxChar ch
= (wxChar
)arg
[i
];
333 const wxChar
*p
= wxStrchr(needEscape
, ch
);
336 str
+= wxString::Format(wxT("\\%c"), escapes
[p
- needEscape
]);
337 else if (wxIscntrl(ch
))
338 str
+= wxString::Format(wxT("\\%03o"), ch
);
343 return str
.length() == arg
.length() && str
.find(' ') == wxString::npos
?
344 str
: wxT("\"") + str
+ wxT("\"");
348 ///////////////////////////////////////////////////////////////////////////////
351 class RegExTestSuite
: public TestSuite
354 RegExTestSuite(string name
) : TestSuite(name
) { }
355 void add(const char *mode
, const char *id
, const char *flags
,
356 const char *pattern
, const char *data
, const char *expected
, ...);
359 // Add a testcase to the suite
361 void RegExTestSuite::add(
367 const char *expected
, ...)
369 string name
= getName() + "." + id
;
371 vector
<const char *> expected_results
;
374 for (va_start(ap
, expected
); expected
; expected
= va_arg(ap
, const char *))
375 expected_results
.push_back(expected
);
380 addTest(new RegExTestCase(
381 name
, mode
, id
, flags
, pattern
, data
, expected_results
));
383 catch (Exception
& e
) {
384 wxLogInfo(wxString::Format(wxT("skipping: %s\n %s\n"),
385 wxString(name
.c_str(), wxConvUTF8
).c_str(),
386 wxString(e
.what(), wxConvUTF8
).c_str()));
391 // Include the generated tests
396 #endif // wxHAS_REGEX_ADVANCED
398 #endif // wxUSE_REGEX