]>
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 "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 | _T("\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(_T("\\%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(_T("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(_T("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 | (_T("/") + Conv(pattern) + _T("/") + 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 << _T("'") << Conv(text) << _T("' =~ /") << Conv(pattern) << _T("/") | |
276 | << FlagStr(flags); | |
277 | name.Replace(_T("\n"), _T("\\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 << _T("'") << Conv(text) << _T("' =~ s/") << Conv(pattern) << _T("/") | |
296 | << Conv(replacement) << _T("/g") << FlagStr(flags); | |
297 | name.Replace(_T("\n"), _T("\\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 += _T(" | wxRE_ADVANCED"); break; | |
318 | #endif | |
319 | case wxRE_BASIC: str += _T(" | wxRE_BASIC"); break; | |
320 | case wxRE_ICASE: str += _T(" | wxRE_ICASE"); break; | |
321 | case wxRE_NOSUB: str += _T(" | wxRE_NOSUB"); break; | |
322 | case wxRE_NEWLINE: str += _T(" | wxRE_NEWLINE"); break; | |
323 | case wxRE_NOTBOL: str += _T(" | wxRE_NOTBOL"); break; | |
324 | case wxRE_NOTEOL: str += _T(" | wxRE_NOTEOL"); break; | |
325 | default: wxFAIL; break; | |
326 | } | |
327 | } | |
328 | ||
329 | return _T(" (") + str.Mid(3) + _T(")"); | |
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 it's own registry so that these tests can be run alone | |
336 | CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(wxRegExTestSuite, "wxRegExTestSuite"); | |
337 | ||
338 | ||
339 | #endif // wxUSE_REGEX |