Patch 1053127 - Test fixes.
[wxWidgets.git] / tests / regex / wxregextest.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: tests/regex/wxregex.cpp
3 // Purpose: Test wxRegEx
4 // Author: Vadim Zeitlin, Mike Wetherell
5 // RCS-ID: $Id$
6 // Copyright: Vadim Zeitlin, Mike Wetherell
7 // Licence: wxWidgets licence
8 ///////////////////////////////////////////////////////////////////////////////
9
10 #include "wx/wxprec.h"
11
12 #ifdef __BORLANDC__
13 # pragma hdrstop
14 #endif
15
16 #ifndef WX_PRECOMP
17 # include "wx/wx.h"
18 #endif
19
20 #if wxUSE_REGEX
21
22 #include "wx/regex.h"
23 #include "wx/cppunit.h"
24 #include "wx/tokenzr.h"
25 #include <string>
26
27 using CppUnit::Test;
28 using CppUnit::TestCase;
29 using CppUnit::TestSuite;
30 using std::string;
31
32
33 ///////////////////////////////////////////////////////////////////////////////
34 // Compile Test
35
36 class RegExCompileTestCase : public TestCase
37 {
38 public:
39 RegExCompileTestCase(const char *name, const wxString& pattern,
40 bool correct, int flags)
41 : TestCase(name),
42 m_pattern(pattern),
43 m_correct(correct),
44 m_flags(flags)
45 { }
46
47 protected:
48 void runTest();
49
50 private:
51 wxString m_pattern;
52 bool m_correct;
53 int m_flags;
54 };
55
56 void RegExCompileTestCase::runTest()
57 {
58 wxRegEx re;
59 bool ok = re.Compile(m_pattern, m_flags);
60
61 if (m_correct)
62 CPPUNIT_ASSERT_MESSAGE("compile failed", ok);
63 else
64 CPPUNIT_ASSERT_MESSAGE("compile succeeded (should fail)", !ok);
65 }
66
67
68 ///////////////////////////////////////////////////////////////////////////////
69 // Match Test
70
71 class RegExMatchTestCase : public TestCase
72 {
73 public:
74 RegExMatchTestCase(const char *name, const wxString& pattern,
75 const wxString& text, const char *expected,
76 int flags)
77 : TestCase(name),
78 m_pattern(pattern),
79 m_text(text),
80 m_expected(expected),
81 m_flags(flags)
82 { }
83
84 protected:
85 void runTest();
86
87 private:
88 wxString m_pattern;
89 wxString m_text;
90 const char *m_expected;
91 int m_flags;
92 };
93
94 void RegExMatchTestCase::runTest()
95 {
96 int compileFlags = m_flags & ~(wxRE_NOTBOL | wxRE_NOTEOL);
97 int matchFlags = m_flags & (wxRE_NOTBOL | wxRE_NOTEOL);
98
99 wxRegEx re(m_pattern, compileFlags);
100 CPPUNIT_ASSERT_MESSAGE("compile failed", re.IsValid());
101
102 bool ok = re.Matches(m_text, matchFlags);
103
104 if (m_expected) {
105 CPPUNIT_ASSERT_MESSAGE("match failed", ok);
106
107 wxStringTokenizer tkz(wxString(m_expected, *wxConvCurrent),
108 _T("\t"), wxTOKEN_RET_EMPTY);
109 size_t i;
110
111 for (i = 0; i < re.GetMatchCount() && tkz.HasMoreTokens(); i++) {
112 wxString expected = tkz.GetNextToken();
113 wxString result = re.GetMatch(m_text, i);
114
115 wxString msgstr;
116 msgstr.Printf(_T("\\%d == '%s' (expected '%s')"),
117 (int)i, result.c_str(), expected.c_str());
118
119 CPPUNIT_ASSERT_MESSAGE((const char*)msgstr.mb_str(),
120 result == expected);
121 }
122
123 if ((m_flags & wxRE_NOSUB) == 0)
124 CPPUNIT_ASSERT(re.GetMatchCount() == i);
125 }
126 else {
127 CPPUNIT_ASSERT_MESSAGE("match succeeded (should fail)", !ok);
128 }
129 }
130
131
132 ///////////////////////////////////////////////////////////////////////////////
133 // Replacement Test
134
135 class RegExReplaceTestCase : public TestCase
136 {
137 public:
138 RegExReplaceTestCase(const char *name, const wxString& pattern,
139 const wxString& text, const wxString& repl,
140 const wxString& expected, size_t count, int flags)
141 : TestCase(name),
142 m_pattern(pattern),
143 m_text(text),
144 m_repl(repl),
145 m_expected(expected),
146 m_count(count),
147 m_flags(flags)
148 { }
149
150 protected:
151 void runTest();
152
153 private:
154 wxString m_pattern;
155 wxString m_text;
156 wxString m_repl;
157 wxString m_expected;
158 size_t m_count;
159 int m_flags;
160 };
161
162 void RegExReplaceTestCase::runTest()
163 {
164 wxRegEx re(m_pattern, m_flags);
165
166 wxString text(m_text);
167 size_t nRepl = re.Replace(&text, m_repl);
168
169 wxString msgstr;
170 msgstr.Printf(_T("returns '%s' (expected '%s')"), text.c_str(), m_expected.c_str());
171 CPPUNIT_ASSERT_MESSAGE((const char*)msgstr.mb_str(), text == m_expected);
172
173 msgstr.Printf(_T("matches %d times (expected %d)"), nRepl, m_count);
174 CPPUNIT_ASSERT_MESSAGE((const char*)msgstr.mb_str(), nRepl == m_count);
175 }
176
177
178 ///////////////////////////////////////////////////////////////////////////////
179 // The suite
180
181 class wxRegExTestSuite : public TestSuite
182 {
183 public:
184 wxRegExTestSuite() : TestSuite("wxRegExTestSuite") { }
185 static Test *suite();
186
187 private:
188 void add(const char *pattern, bool correct, int flags = wxRE_DEFAULT);
189 void add(const char *pattern, const char *text,
190 const char *expected = NULL, int flags = wxRE_DEFAULT);
191 void add(const char *pattern, const char *text, const char *replacement,
192 const char *expected, size_t count, int flags = wxRE_DEFAULT);
193
194 static wxString FlagStr(int flags);
195 static wxString Conv(const char *str) { return wxString(str, *wxConvCurrent); }
196 };
197
198 // Build the suite (static)
199 //
200 Test *wxRegExTestSuite::suite()
201 {
202 wxRegExTestSuite *suite = new wxRegExTestSuite;
203
204 // Compile tests
205 // pattern, expected result
206 suite->add("foo", true);
207 suite->add("foo(", false);
208 suite->add("foo(bar", false);
209 suite->add("foo(bar)", true);
210 suite->add("foo[", false);
211 suite->add("foo[bar", false);
212 suite->add("foo[bar]", true);
213 suite->add("foo{1", false);
214 suite->add("foo{1}", true);
215 suite->add("foo{1,2}", true);
216 suite->add("foo*", true);
217 suite->add("foo+", true);
218 suite->add("foo?", true);
219
220 // Match tests
221 // pattern, text, expected results (match, followed by submatches
222 // tab separated, or NULL for no match expected)
223 suite->add("foo", "bar");
224 suite->add("foo", "foobar", "foo");
225 suite->add("^foo", "foobar", "foo");
226 suite->add("^foo", "barfoo");
227 suite->add("bar$", "barbar", "bar");
228 suite->add("bar$", "barbar ");
229 suite->add("OoBa", "FoObAr", "oObA", wxRE_ICASE);
230 suite->add("^[A-Z].*$", "AA\nbb\nCC", "AA\nbb\nCC");
231 suite->add("^[A-Z].*$", "AA\nbb\nCC", "AA", wxRE_NEWLINE);
232 suite->add("^[a-z].*$", "AA\nbb\nCC", "bb", wxRE_NEWLINE);
233 suite->add("^[A-Z].*$", "AA\nbb\nCC", "CC", wxRE_NEWLINE | wxRE_NOTBOL);
234 suite->add("^[A-Z].*$", "AA\nbb\nCC", NULL, wxRE_NEWLINE | wxRE_NOTBOL | wxRE_NOTEOL);
235 suite->add("([[:alpha:]]+) ([[:alpha:]]+) ([[:digit:]]+).* ([[:digit:]]+)$",
236 "Fri Jul 13 18:37:52 CEST 2001",
237 "Fri Jul 13 18:37:52 CEST 2001\tFri\tJul\t13\t2001");
238
239 // Replace tests
240 // pattern, text, replacement, expected result and number of matches
241 const char *patn = "([a-z]+)[^0-9]*([0-9]+)";
242 suite->add(patn, "foo123", "bar", "bar", 1);
243 suite->add(patn, "foo123", "\\2\\1", "123foo", 1);
244 suite->add(patn, "foo_123", "\\2\\1", "123foo", 1);
245 suite->add(patn, "123foo", "bar", "123foo", 0);
246 suite->add(patn, "123foo456foo", "&&", "123foo456foo456foo", 1);
247 suite->add(patn, "123foo456foo", "\\0\\0", "123foo456foo456foo", 1);
248 suite->add(patn, "foo123foo123", "bar", "barbar", 2);
249 suite->add(patn, "foo123_foo456_foo789", "bar", "bar_bar_bar", 3);
250
251 return suite;
252 }
253
254 // Add a compile test
255 //
256 void wxRegExTestSuite::add(
257 const char *pattern,
258 bool correct,
259 int flags /*=wxRE_DEFAULT*/)
260 {
261 addTest(new RegExCompileTestCase(
262 (_T("/") + Conv(pattern) + _T("/") + FlagStr(flags)).mb_str(),
263 Conv(pattern), correct, flags));
264 }
265
266 // Add a match test
267 //
268 void wxRegExTestSuite::add(
269 const char *pattern,
270 const char *text,
271 const char *expected /*=NULL*/,
272 int flags /*=wxRE_DEFAULT*/)
273 {
274 wxString name;
275
276 name << _T("'") << Conv(text) << _T("' =~ /") << Conv(pattern) << _T("/")
277 << FlagStr(flags);
278 name.Replace(_T("\n"), _T("\\n"));
279
280 addTest(new RegExMatchTestCase(name.mb_str(), Conv(pattern),
281 Conv(text), expected, flags));
282 }
283
284 // Add a replace test
285 //
286 void wxRegExTestSuite::add(
287 const char *pattern,
288 const char *text,
289 const char *replacement,
290 const char *expected,
291 size_t count,
292 int flags /*=wxRE_DEFAULT*/)
293 {
294 wxString name;
295
296 name << _T("'") << Conv(text) << _T("' =~ s/") << Conv(pattern) << _T("/")
297 << Conv(replacement) << _T("/g") << FlagStr(flags);
298 name.Replace(_T("\n"), _T("\\n"));
299
300 addTest(new RegExReplaceTestCase(
301 name.mb_str(), Conv(pattern), Conv(text),
302 Conv(replacement), Conv(expected), count, flags));
303 }
304
305 // Display string for the flags
306 //
307 wxString wxRegExTestSuite::FlagStr(int flags)
308 {
309 wxString str;
310
311 if (!flags)
312 return str;
313
314 for (int i = 0; (unsigned)flags >> i; i++) {
315 switch (flags & (1 << i)) {
316 case 0: break;
317 #ifdef wxHAS_REGEX_ADVANCED
318 case wxRE_ADVANCED: str += _T(" | wxRE_ADVANCED"); break;
319 #endif
320 case wxRE_BASIC: str += _T(" | wxRE_BASIC"); break;
321 case wxRE_ICASE: str += _T(" | wxRE_ICASE"); break;
322 case wxRE_NOSUB: str += _T(" | wxRE_NOSUB"); break;
323 case wxRE_NEWLINE: str += _T(" | wxRE_NEWLINE"); break;
324 case wxRE_NOTBOL: str += _T(" | wxRE_NOTBOL"); break;
325 case wxRE_NOTEOL: str += _T(" | wxRE_NOTEOL"); break;
326 default: wxFAIL; break;
327 }
328 }
329
330 return _T(" (") + str.Mid(3) + _T(")");
331 };
332
333 // register in the unnamed registry so that these tests are run by default
334 CPPUNIT_TEST_SUITE_REGISTRATION(wxRegExTestSuite);
335
336 // also include in it's own registry so that these tests can be run alone
337 CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(wxRegExTestSuite, "wxRegExTestSuite");
338
339
340 #endif // wxUSE_REGEX