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