]>
Commit | Line | Data |
---|---|---|
bc10103e VS |
1 | /////////////////////////////////////////////////////////////////////////////// |
2 | // Name: tests/regex/wxregex.cpp | |
3 | // Purpose: Test wxRegEx | |
4 | // Author: Vadim Zeitlin, Mike Wetherell | |
bc10103e | 5 | // Copyright: Vadim Zeitlin, Mike Wetherell |
526954c5 | 6 | // Licence: wxWindows licence |
bc10103e VS |
7 | /////////////////////////////////////////////////////////////////////////////// |
8 | ||
8899b155 | 9 | #include "testprec.h" |
bc10103e VS |
10 | |
11 | #ifdef __BORLANDC__ | |
12 | # pragma hdrstop | |
13 | #endif | |
14 | ||
15 | #ifndef WX_PRECOMP | |
16 | # include "wx/wx.h" | |
17 | #endif | |
18 | ||
19 | #if wxUSE_REGEX | |
20 | ||
21 | #include "wx/regex.h" | |
bc10103e VS |
22 | #include "wx/tokenzr.h" |
23 | #include <string> | |
24 | ||
3e5f6c1c WS |
25 | using CppUnit::Test; |
26 | using CppUnit::TestCase; | |
27 | using CppUnit::TestSuite; | |
28 | using std::string; | |
bc10103e VS |
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), | |
9a83f860 | 106 | wxT("\t"), wxTOKEN_RET_EMPTY); |
bc10103e VS |
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; | |
9a83f860 | 114 | msgstr.Printf(wxT("\\%d == '%s' (expected '%s')"), |
bc10103e | 115 | (int)i, result.c_str(), expected.c_str()); |
bc10103e | 116 | |
c33230b1 VS |
117 | CPPUNIT_ASSERT_MESSAGE((const char*)msgstr.mb_str(), |
118 | result == expected); | |
bc10103e VS |
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) | |
3e5f6c1c | 146 | { } |
bc10103e VS |
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; | |
9a83f860 | 168 | msgstr.Printf(wxT("returns '%s' (expected '%s')"), text.c_str(), m_expected.c_str()); |
c33230b1 | 169 | CPPUNIT_ASSERT_MESSAGE((const char*)msgstr.mb_str(), text == m_expected); |
bc10103e | 170 | |
9a83f860 | 171 | msgstr.Printf(wxT("matches %d times (expected %d)"), (int)nRepl, (int)m_count); |
c33230b1 | 172 | CPPUNIT_ASSERT_MESSAGE((const char*)msgstr.mb_str(), nRepl == m_count); |
bc10103e VS |
173 | } |
174 | ||
175 | ||
176 | /////////////////////////////////////////////////////////////////////////////// | |
177 | // The suite | |
178 | ||
179 | class wxRegExTestSuite : public TestSuite | |
180 | { | |
181 | public: | |
182 | wxRegExTestSuite() : TestSuite("wxRegExTestSuite") { } | |
183 | static Test *suite(); | |
184 | ||
185 | private: | |
186 | void add(const char *pattern, bool correct, int flags = wxRE_DEFAULT); | |
187 | void add(const char *pattern, const char *text, | |
188 | const char *expected = NULL, int flags = wxRE_DEFAULT); | |
189 | void add(const char *pattern, const char *text, const char *replacement, | |
190 | const char *expected, size_t count, int flags = wxRE_DEFAULT); | |
191 | ||
192 | static wxString FlagStr(int flags); | |
193 | static wxString Conv(const char *str) { return wxString(str, *wxConvCurrent); } | |
194 | }; | |
195 | ||
196 | // Build the suite (static) | |
197 | // | |
198 | Test *wxRegExTestSuite::suite() | |
199 | { | |
200 | wxRegExTestSuite *suite = new wxRegExTestSuite; | |
201 | ||
202 | // Compile tests | |
203 | // pattern, expected result | |
204 | suite->add("foo", true); | |
205 | suite->add("foo(", false); | |
206 | suite->add("foo(bar", false); | |
207 | suite->add("foo(bar)", true); | |
208 | suite->add("foo[", false); | |
209 | suite->add("foo[bar", false); | |
210 | suite->add("foo[bar]", true); | |
211 | suite->add("foo{1", false); | |
212 | suite->add("foo{1}", true); | |
213 | suite->add("foo{1,2}", true); | |
214 | suite->add("foo*", true); | |
215 | suite->add("foo+", true); | |
216 | suite->add("foo?", true); | |
217 | ||
218 | // Match tests | |
219 | // pattern, text, expected results (match, followed by submatches | |
220 | // tab separated, or NULL for no match expected) | |
221 | suite->add("foo", "bar"); | |
222 | suite->add("foo", "foobar", "foo"); | |
223 | suite->add("^foo", "foobar", "foo"); | |
224 | suite->add("^foo", "barfoo"); | |
225 | suite->add("bar$", "barbar", "bar"); | |
226 | suite->add("bar$", "barbar "); | |
227 | suite->add("OoBa", "FoObAr", "oObA", wxRE_ICASE); | |
228 | suite->add("^[A-Z].*$", "AA\nbb\nCC", "AA\nbb\nCC"); | |
229 | suite->add("^[A-Z].*$", "AA\nbb\nCC", "AA", wxRE_NEWLINE); | |
230 | suite->add("^[a-z].*$", "AA\nbb\nCC", "bb", wxRE_NEWLINE); | |
231 | suite->add("^[A-Z].*$", "AA\nbb\nCC", "CC", wxRE_NEWLINE | wxRE_NOTBOL); | |
232 | suite->add("^[A-Z].*$", "AA\nbb\nCC", NULL, wxRE_NEWLINE | wxRE_NOTBOL | wxRE_NOTEOL); | |
233 | suite->add("([[:alpha:]]+) ([[:alpha:]]+) ([[:digit:]]+).* ([[:digit:]]+)$", | |
234 | "Fri Jul 13 18:37:52 CEST 2001", | |
235 | "Fri Jul 13 18:37:52 CEST 2001\tFri\tJul\t13\t2001"); | |
236 | ||
237 | // Replace tests | |
238 | // pattern, text, replacement, expected result and number of matches | |
239 | const char *patn = "([a-z]+)[^0-9]*([0-9]+)"; | |
240 | suite->add(patn, "foo123", "bar", "bar", 1); | |
241 | suite->add(patn, "foo123", "\\2\\1", "123foo", 1); | |
242 | suite->add(patn, "foo_123", "\\2\\1", "123foo", 1); | |
243 | suite->add(patn, "123foo", "bar", "123foo", 0); | |
244 | suite->add(patn, "123foo456foo", "&&", "123foo456foo456foo", 1); | |
245 | suite->add(patn, "123foo456foo", "\\0\\0", "123foo456foo456foo", 1); | |
246 | suite->add(patn, "foo123foo123", "bar", "barbar", 2); | |
247 | suite->add(patn, "foo123_foo456_foo789", "bar", "bar_bar_bar", 3); | |
248 | ||
249 | return suite; | |
250 | } | |
251 | ||
252 | // Add a compile test | |
253 | // | |
254 | void wxRegExTestSuite::add( | |
255 | const char *pattern, | |
256 | bool correct, | |
257 | int flags /*=wxRE_DEFAULT*/) | |
258 | { | |
259 | addTest(new RegExCompileTestCase( | |
9a83f860 | 260 | (wxT("/") + Conv(pattern) + wxT("/") + FlagStr(flags)).mb_str(), |
bc10103e VS |
261 | Conv(pattern), correct, flags)); |
262 | } | |
263 | ||
264 | // Add a match test | |
265 | // | |
266 | void wxRegExTestSuite::add( | |
267 | const char *pattern, | |
268 | const char *text, | |
269 | const char *expected /*=NULL*/, | |
270 | int flags /*=wxRE_DEFAULT*/) | |
271 | { | |
272 | wxString name; | |
273 | ||
9a83f860 | 274 | name << wxT("'") << Conv(text) << wxT("' =~ /") << Conv(pattern) << wxT("/") |
bc10103e | 275 | << FlagStr(flags); |
9a83f860 | 276 | name.Replace(wxT("\n"), wxT("\\n")); |
bc10103e VS |
277 | |
278 | addTest(new RegExMatchTestCase(name.mb_str(), Conv(pattern), | |
279 | Conv(text), expected, flags)); | |
280 | } | |
281 | ||
282 | // Add a replace test | |
283 | // | |
284 | void wxRegExTestSuite::add( | |
285 | const char *pattern, | |
286 | const char *text, | |
287 | const char *replacement, | |
288 | const char *expected, | |
289 | size_t count, | |
290 | int flags /*=wxRE_DEFAULT*/) | |
291 | { | |
292 | wxString name; | |
293 | ||
9a83f860 VZ |
294 | name << wxT("'") << Conv(text) << wxT("' =~ s/") << Conv(pattern) << wxT("/") |
295 | << Conv(replacement) << wxT("/g") << FlagStr(flags); | |
296 | name.Replace(wxT("\n"), wxT("\\n")); | |
bc10103e VS |
297 | |
298 | addTest(new RegExReplaceTestCase( | |
299 | name.mb_str(), Conv(pattern), Conv(text), | |
300 | Conv(replacement), Conv(expected), count, flags)); | |
301 | } | |
302 | ||
303 | // Display string for the flags | |
304 | // | |
305 | wxString wxRegExTestSuite::FlagStr(int flags) | |
306 | { | |
307 | wxString str; | |
308 | ||
309 | if (!flags) | |
310 | return str; | |
311 | ||
312 | for (int i = 0; (unsigned)flags >> i; i++) { | |
313 | switch (flags & (1 << i)) { | |
314 | case 0: break; | |
315 | #ifdef wxHAS_REGEX_ADVANCED | |
9a83f860 | 316 | case wxRE_ADVANCED: str += wxT(" | wxRE_ADVANCED"); break; |
bc10103e | 317 | #endif |
9a83f860 VZ |
318 | case wxRE_BASIC: str += wxT(" | wxRE_BASIC"); break; |
319 | case wxRE_ICASE: str += wxT(" | wxRE_ICASE"); break; | |
320 | case wxRE_NOSUB: str += wxT(" | wxRE_NOSUB"); break; | |
321 | case wxRE_NEWLINE: str += wxT(" | wxRE_NEWLINE"); break; | |
322 | case wxRE_NOTBOL: str += wxT(" | wxRE_NOTBOL"); break; | |
323 | case wxRE_NOTEOL: str += wxT(" | wxRE_NOTEOL"); break; | |
bc10103e VS |
324 | default: wxFAIL; break; |
325 | } | |
326 | } | |
327 | ||
9a83f860 | 328 | return wxT(" (") + str.Mid(3) + wxT(")"); |
93a800a9 | 329 | } |
bc10103e VS |
330 | |
331 | // register in the unnamed registry so that these tests are run by default | |
332 | CPPUNIT_TEST_SUITE_REGISTRATION(wxRegExTestSuite); | |
333 | ||
e3778b4d | 334 | // also include in its own registry so that these tests can be run alone |
bc10103e VS |
335 | CPPUNIT_TEST_SUITE_NAMED_REGISTRATION(wxRegExTestSuite, "wxRegExTestSuite"); |
336 | ||
337 | ||
338 | #endif // wxUSE_REGEX |