]>
Commit | Line | Data |
---|---|---|
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 namespace std; | |
28 | using namespace CppUnit; | |
29 | ||
30 | ||
31 | /////////////////////////////////////////////////////////////////////////////// | |
32 | // Compile Test | |
33 | ||
34 | class RegExCompileTestCase : public TestCase | |
35 | { | |
36 | public: | |
37 | RegExCompileTestCase(const char *name, const wxString& pattern, | |
38 | bool correct, int flags) | |
39 | : TestCase(name), | |
40 | m_pattern(pattern), | |
41 | m_correct(correct), | |
42 | m_flags(flags) | |
43 | { } | |
44 | ||
45 | protected: | |
46 | void runTest(); | |
47 | ||
48 | private: | |
49 | wxString m_pattern; | |
50 | bool m_correct; | |
51 | int m_flags; | |
52 | }; | |
53 | ||
54 | void RegExCompileTestCase::runTest() | |
55 | { | |
56 | wxRegEx re; | |
57 | bool ok = re.Compile(m_pattern, m_flags); | |
58 | ||
59 | if (m_correct) | |
60 | CPPUNIT_ASSERT_MESSAGE("compile failed", ok); | |
61 | else | |
62 | CPPUNIT_ASSERT_MESSAGE("compile succeeded (should fail)", !ok); | |
63 | } | |
64 | ||
65 | ||
66 | /////////////////////////////////////////////////////////////////////////////// | |
67 | // Match Test | |
68 | ||
69 | class RegExMatchTestCase : public TestCase | |
70 | { | |
71 | public: | |
72 | RegExMatchTestCase(const char *name, const wxString& pattern, | |
73 | const wxString& text, const char *expected, | |
74 | int flags) | |
75 | : TestCase(name), | |
76 | m_pattern(pattern), | |
77 | m_text(text), | |
78 | m_expected(expected), | |
79 | m_flags(flags) | |
80 | { } | |
81 | ||
82 | protected: | |
83 | void runTest(); | |
84 | ||
85 | private: | |
86 | wxString m_pattern; | |
87 | wxString m_text; | |
88 | const char *m_expected; | |
89 | int m_flags; | |
90 | }; | |
91 | ||
92 | void RegExMatchTestCase::runTest() | |
93 | { | |
94 | int compileFlags = m_flags & ~(wxRE_NOTBOL | wxRE_NOTEOL); | |
95 | int matchFlags = m_flags & (wxRE_NOTBOL | wxRE_NOTEOL); | |
96 | ||
97 | wxRegEx re(m_pattern, compileFlags); | |
98 | CPPUNIT_ASSERT_MESSAGE("compile failed", re.IsValid()); | |
99 | ||
100 | bool ok = re.Matches(m_text, matchFlags); | |
101 | ||
102 | if (m_expected) { | |
103 | CPPUNIT_ASSERT_MESSAGE("match failed", ok); | |
104 | ||
105 | wxStringTokenizer tkz(wxString(m_expected, *wxConvCurrent), | |
106 | _T("\t"), wxTOKEN_RET_EMPTY); | |
107 | size_t i; | |
108 | ||
109 | for (i = 0; i < re.GetMatchCount() && tkz.HasMoreTokens(); i++) { | |
110 | wxString expected = tkz.GetNextToken(); | |
111 | wxString result = re.GetMatch(m_text, i); | |
112 | ||
113 | wxString msgstr; | |
114 | msgstr.Printf(_T("\\%d == '%s' (expected '%s')"), | |
115 | (int)i, result.c_str(), expected.c_str()); | |
116 | const char *msg = msgstr.mb_str(); | |
117 | ||
118 | CPPUNIT_ASSERT_MESSAGE(msg, result == expected); | |
119 | } | |
120 | ||
121 | if ((m_flags & wxRE_NOSUB) == 0) | |
122 | CPPUNIT_ASSERT(re.GetMatchCount() == i); | |
123 | } | |
124 | else { | |
125 | CPPUNIT_ASSERT_MESSAGE("match succeeded (should fail)", !ok); | |
126 | } | |
127 | } | |
128 | ||
129 | ||
130 | /////////////////////////////////////////////////////////////////////////////// | |
131 | // Replacement Test | |
132 | ||
133 | class RegExReplaceTestCase : public TestCase | |
134 | { | |
135 | public: | |
136 | RegExReplaceTestCase(const char *name, const wxString& pattern, | |
137 | const wxString& text, const wxString& repl, | |
138 | const wxString& expected, size_t count, int flags) | |
139 | : TestCase(name), | |
140 | m_pattern(pattern), | |
141 | m_text(text), | |
142 | m_repl(repl), | |
143 | m_expected(expected), | |
144 | m_count(count), | |
145 | m_flags(flags) | |
146 | { } | |
147 | ||
148 | protected: | |
149 | void runTest(); | |
150 | ||
151 | private: | |
152 | wxString m_pattern; | |
153 | wxString m_text; | |
154 | wxString m_repl; | |
155 | wxString m_expected; | |
156 | size_t m_count; | |
157 | int m_flags; | |
158 | }; | |
159 | ||
160 | void RegExReplaceTestCase::runTest() | |
161 | { | |
162 | wxRegEx re(m_pattern, m_flags); | |
163 | ||
164 | wxString text(m_text); | |
165 | size_t nRepl = re.Replace(&text, m_repl); | |
166 | ||
167 | wxString msgstr; | |
168 | msgstr.Printf(_T("returns '%s' (expected '%s')"), text.c_str(), m_expected.c_str()); | |
169 | const char *msg = msgstr.mb_str(); | |
170 | CPPUNIT_ASSERT_MESSAGE(msg, text == m_expected); | |
171 | ||
172 | msgstr.Printf(_T("matches %d times (expected %d)"), nRepl, m_count); | |
173 | msg = msgstr.mb_str(); | |
174 | CPPUNIT_ASSERT_MESSAGE(msg, 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 |