1
2 #include <reflex/boostmatcher.h>
3
4 // #define INTERACTIVE // for interactive mode testing
5
banner(const char * title)6 static void banner(const char *title)
7 {
8 int i;
9 printf("\n\n/");
10 for (i = 0; i < 78; i++)
11 putchar('*');
12 printf("\\\n *%76s*\n * %-75s*\n *%76s*\n\\", "", title, "");
13 for (i = 0; i < 78; i++)
14 putchar('*');
15 printf("/\n\n");
16 }
17
error(const char * text)18 static void error(const char *text)
19 {
20 std::cout << "FAILED: " << text << std::endl;
21 exit(EXIT_FAILURE);
22 }
23
24 using namespace reflex;
25
26 class WrappedMatcher : public BoostPosixMatcher {
27 public:
WrappedMatcher()28 WrappedMatcher() : BoostPosixMatcher(), source(0)
29 { }
30 private:
wrap()31 virtual bool wrap()
32 {
33 switch (source++)
34 {
35 case 0: in = "Hello World!";
36 return true;
37 case 1: in = "How now brown cow.";
38 return true;
39 case 2: in = "An apple a day.";
40 return true;
41 }
42 return false;
43 }
44 int source;
45 };
46
47 struct Test {
48 const char *pattern;
49 const char *popts;
50 const char *mopts;
51 const char *cstring;
52 size_t accepts[32];
53 };
54
55 Test tests[] = {
56 { "ab", "", "", "ab", { 1 } },
57 { "ab", "", "", "abab", { 1, 1 } },
58 { "ab|xy", "", "", "abxy", { 1, 2 } },
59 { "a(p|q)z", "", "", "apzaqz", { 1, 1 } },
60 // DFA edge compaction test (only applicable to RE/flex)
61 { "[a-cg-ik]z|d|[e-g]|j|y|[x-z]|.|\\n", "", "", "azz", { 1, 6 } },
62 // POSIX character classes
63 {
64 "\\x7E-"
65 "[[:space:]]-"
66 "[[:xdigit:]]-"
67 "[[:cntrl:]]-"
68 "[[:print:]]-"
69 "[[:alnum:]]-"
70 "[[:alpha:]]-"
71 "[[:blank:]]-"
72 "[[:digit:]]-"
73 "[[:graph:]]-"
74 "[[:lower:]]-"
75 "[[:punct:]]-"
76 "[[:upper:]]-"
77 "[[:word:]]", "", "", "\x7E-\r-F-\x01-&-0-A-\t-0-#-l-.-U-_", { 1 } },
78 {
79 "\\x7E-"
80 "\\p{Space}-"
81 "\\p{XDigit}-"
82 "\\p{Cntrl}-"
83 "\\p{Print}-"
84 "\\p{Alnum}-"
85 "\\p{Alpha}-"
86 "\\p{Blank}-"
87 "\\p{Digit}-"
88 "\\p{Graph}-"
89 "\\p{Lower}-"
90 "\\p{Punct}-"
91 "\\p{Upper}-"
92 "\\p{Word}", "", "", "\x7E-\r-F-\x01-&-0-A-\t-0-#-l-.-U-_", { 1 } },
93 // Pattern option i
94 { "(?i:abc)", "", "", "abcABC", { 1, 1 } },
95 { "(?i)abc|xyz", "", "", "abcABCxyzXYZ", { 1, 1, 2, 2 } },
96 { "(?i:abc)|xyz", "", "", "abcABCxyz", { 1, 1, 2 } },
97 { "(?i:abc)|(?i:xyz)", "", "", "abcABCxyzXYZ", { 1, 1, 2, 2 } },
98 { "(?i)abc|(?-i:xyz)|(?-i:XYZ)", "", "", "abcABCxyzXYZ", { 1, 1, 2, 3 } },
99 { "(?i:abc(?-i:xyz))|ABCXYZ", "", "", "abcxyzABCxyzABCXYZ", { 1, 1, 2 } },
100 // Pattern option x
101 { "(?x) a\tb\n c | ( xy ) z ?", "", "", "abcxy", { 1, 2 } },
102 { "(?x: a b\n c)", "", "", "abc", { 1 } },
103 { "(?x) a b c\n|\n# COMMENT\n x y z", "", "", "abcxyz", { 1, 2 } },
104 // { "(?x) a b c\n|\n/* COMMENT\n*/ x y z", "", "", "abcxyz", { 1, 2 } }, // Boost does not support /*...*/
105 { "(?# test option (?x:... )(?x: a b c)|x y z", "", "", "abcx y z", { 1, 2 } },
106 // Pattern option s
107 { "(?s).", "", "", "a\n", { 1, 1 } },
108 { "(?s:.)", "", "", "a\n", { 1, 1 } },
109 { "(?s).", "", "", "a\n", { 1, 1 } },
110 // Anchors \A, \Z, ^, and $ (Boost.Regex matches \n, \r and \f as newlines)
111 { "\\Aa\\Z", "", "", "a", { 1 } },
112 { "^a$", "", "", "a", { 1 } },
113 { "(?m)^a$|\\n", "m", "", "a\na", { 1, 2, 1 } },
114 { "(?m)^a|a$|a|\\n", "m", "", "aa\naaa", { 1, 2, 4, 1, 3, 2 } },
115 #ifndef INTERACTIVE
116 { "(?m)\\Aa\\Z|\\Aa|a\\Z|^a$|^a|a$|a|^ab$|^ab|ab$|ab|\\n", "m", "", "a\na\naa\naaa\nab\nabab\nababab\na", { 2, 12, 4, 12, 5, 6, 12, 5, 7, 6, 12, 8, 12, 9, 10, 12, 9, 11, 10, 12, 3 } }, // boost has a partial match bug when interactive() blk=1
117 #endif
118 // Optional X?
119 { "a?z", "", "", "azz", { 1, 1 } },
120 // Closure X*
121 { "a*z", "", "", "azaazz", { 1, 1, 1 } },
122 // Positive closure X+
123 { "a+z", "", "", "azaaz", { 1, 1 } },
124 // Combi ? * +
125 { "a?b+|a", "", "", "baba", { 1, 1, 2 } },
126 { "a*b+|a", "", "", "baabaa", { 1, 1, 2, 2 } },
127 // Iterations {n,m}
128 { "ab{2}", "", "", "abbabb", { 1, 1 } },
129 { "ab{2,3}", "", "", "abbabbb", { 1, 1 } },
130 { "ab{2,}", "", "", "abbabbbabbbb", { 1, 1, 1 } },
131 { "ab{0,}", "", "", "a", { 1 } },
132 { "(ab{0,2}c){2}", "", "", "abbcacabcabc", { 1, 1 } },
133 #if 0 // Boost POSIX mode does not support lazy quantifiers
134 // Lazy optional X?
135 { "(a|b)?\?a", "", "", "aaba", { 1, 1, 1 } },
136 { "a(a|b)?\?(?=a|ab)|ac", "", "", "aababac", { 1, 1, 1, 2 } },
137 { "(a|b)?\?(a|b)?\?aa", "", "", "baaaabbaa", { 1, 1, 1 } },
138 { "(a|b)?\?(a|b)?\?(a|b)?\?aaa", "", "", "baaaaaa", { 1, 1 } },
139 { "a?\?b?a", "", "", "aba", { 1, 1 } }, // 'a' 'ba'
140 { "a?\?b?b", "", "", "abb", { 1 } }, // 'abb'
141 // Lazy closure X*
142 { "a*?a", "", "", "aaaa", { 1, 1, 1, 1 } },
143 { "a*?|a|b", "", "", "aab", { 2, 2, 3 } },
144 { "(a|bb)*?abb", "", "", "abbbbabb", { 1, 1 } },
145 { "ab*?|b", "", "", "ab", { 1, 2 } },
146 { "(ab)*?|b", "", "", "b", { 2 } },
147 { "a(ab)*?|b", "", "", "ab", { 1, 2 } },
148 { "(a|b)*?a|c?", "", "", "bbaaac", { 1, 1, 1, 2 } },
149 { "a(a|b)*?a", "", "", "aaaba", { 1, 1 } },
150 { "a(a|b)*?a?\?|b", "", "", "aaaba", { 1, 1, 1, 2, 1 } },
151 { "a(a|b)*?a?", "", "", "aa", { 1 } },
152 { "a(a|b)*?a|a", "", "", "aaaba", { 1, 1 } },
153 { "a(a|b)*?a|a?", "", "", "aaaba", { 1, 1 } },
154 { "a(a|b)*?a|a?\?", "", "", "aaaba", { 1, 1 } },
155 { "a(a|b)*?a|aa?", "", "", "aaaba", { 1, 1 } },
156 { "a(a|b)*?a|aa?\?", "", "", "aaaba", { 1, 1 } },
157 { "ab(ab|cd)*?ab|ab", "", "", "abababcdabab", { 1, 1, 2 } },
158 { "(a|b)(a|b)*?a|a", "", "", "aaabaa", { 1, 1, 2 } },
159 { "(ab|cd)(ab|cd)*?ab|ab", "", "", "abababcdabab", { 1, 1, 2 } },
160 { "(ab)(ab)*?a|b", "", "", "abababa", { 1, 2, 1 } },
161 { "a?(a|b)*?a", "", "", "aaababa", { 1, 1, 1 } },
162 { "(?m)^(a|b)*?a", "m", "", "bba", { 1 } },
163 { "(?m)(a|b)*?a$", "m", "", "bba", { 1 } },
164 { "(?m)^(a|b)*?|b", "m", "", "ab", { 1, 2 } },
165 // Lazy positive closure X+
166 { "a+?a", "", "", "aaaa", { 1, 1 } },
167 { "(a|b)+?", "", "", "ab", { 1, 1 } },
168 { "(a|b)+?a", "", "", "bbaaa", { 1, 1 } },
169 { "(a|b)+?a|c?", "", "", "bbaaa", { 1, 1 } },
170 { "(ab|cd)+?ab|d?", "", "", "cdcdababab", { 1, 1 } },
171 { "(ab)+?a|b", "", "", "abababa", { 1, 2, 1 } },
172 { "(ab)+?ac", "", "", "ababac", { 1 } },
173 { "ABB*?|ab+?|A|a", "", "", "ABab", { 1, 2 } },
174 { "(a|b)+?a|a", "", "", "bbaaa", { 1, 1 } },
175 { "(?m)^(a|b)+?a", "m", "", "abba", { 1 } },
176 { "(?m)(a|b)+?a$", "m", "", "abba", { 1 } },
177 // Lazy iterations {n,m}
178 { "(a|b){0,3}?aaa", "", "", "baaaaaa", { 1, 1 } },
179 { "(a|b){1,3}?aaa", "", "", "baaaaaaa", { 1, 1 } },
180 { "(a|b){1,3}?aaa", "", "", "bbbaaaaaaa", { 1, 1 } },
181 { "(ab|cd){0,3}?ababab", "", "", "cdabababababab", { 1, 1 } },
182 { "(ab|cd){1,3}?ababab", "", "", "cdababababababab", { 1, 1 } },
183 { "(a|b){1,}?a|a", "", "", "bbaaa", { 1, 1 } },
184 { "(a|b){2,}?a|aa", "", "", "bbbaaaa", { 1, 1 } },
185 #endif
186 // Bracket lists
187 { "[a-z]", "", "", "abcxyz", { 1, 1, 1, 1, 1, 1 } },
188 { "[a-d-z]", "", "", "abcd-z", { 1, 1, 1, 1, 1, 1 } },
189 { "[-z]", "", "", "-z", { 1, 1 } },
190 { "[z-]", "", "", "-z", { 1, 1 } },
191 { "[--z]", "", "", "-az", { 1, 1, 1 } },
192 { "[ --]", "", "", " +-", { 1, 1, 1 } },
193 { "[^a-z]", "", "", "A", { 1 } },
194 { "[[:alpha:]]", "", "", "abcxyz", { 1, 1, 1, 1, 1, 1 } },
195 { "[\\p{Alpha}]", "", "", "abcxyz", { 1, 1, 1, 1, 1, 1 } },
196 { "[][]", "", "", "[]", { 1, 1 } },
197 // Lookahead
198 { "a(?=bc)|ab(?=d)|bc|d", "", "", "abcdabd", { 1, 3, 4, 2, 4 } },
199 // { "[ab]+(?=ab)|-|ab", "", "", "aaab-bbab", { 1, 3, 2, 1, 3 } }, // has trailing context (undefined as per POSIX)
200 { "(?m)a(?=b?)|bc", "m", "", "aabc", { 1, 1, 2 } },
201 #ifndef INTERACTIVE
202 { "(?m)a(?=\\nb)|a|^b|\\n", "m", "", "aa\nb\n", { 2, 1, 4, 3, 4 } }, // boost has a partial match bug when interactive() blk=1
203 #endif
204 { "(?m)^a(?=b$)|b|\\n", "m", "", "ab\n", { 1, 2, 3 } },
205 { "(?m)a(?=\n)|a|\\n", "m", "", "aa\n", { 2, 1, 3 } },
206 { "(?m)^( +(?=a)|b)|a|\\n", "m", "", " a\n a\nb\n", { 1, 2, 3, 1, 2, 3, 1, 3 } },
207 // Word boundaries \<, \>, \b, and \B
208 { "\\<a\\>|\\<a|a\\>|a|-", "", "", "a-aaa", { 1, 5, 2, 4, 3 } },
209 { "\\<.*ab\\>|[ab]*|-|\\n", "", "", "-aaa-aaba-aab-\n-aaa", { 3, 1, 3, 4, 3, 2 } },
210 #ifndef INTERACTIVE
211 { "\\<.*\\>", "", "", "abc def", { 1 } }, // boost has a partial match bug when interactive() blk=1
212 #endif
213 { "\\<.*\\>|-", "", "", "abc-", { 1, 2 } },
214 { "\\b.*\\b|-", "", "", "abc-", { 1, 2 } },
215 { "-|\\<.*\\>", "", "", "-abc-", { 1, 2, 1 } },
216 { "-|\\b.*\\b", "", "", "-abc-", { 1, 2, 1 } },
217 { "(-|a)\\<(-|a)\\>(-|a)", "", "", "-a-", { 1 } },
218 { "(-|a)\\b(-|a)\\b(-|a)", "", "", "-a-a-a", { 1, 1 } },
219 { "(-|a)\\B(-|a)\\B(-|a)", "", "", "---aaa", { 1, 1 } },
220 { "\\<(-|a)(-|a)\\>| ", "", "", "aa aa", { 1, 2, 1 } },
221 { "\\b(-|a)(-|a)\\b| ", "", "", "aa aa", { 1, 2, 1 } },
222 #ifndef INTERACTIVE
223 { "\\B(-|a)(-|a)\\B|b|#", "", "", "baab#--#", { 2, 1, 2, 3, 1, 3 } }, // boost has a partial match bug when interactive() blk=1
224 #endif
225 { "-\\b(-|a)(-|a)\\b", "", "", "-aa", { 1 } },
226 { "a\\b(-|a)(-|a)\\b", "", "", "a-a", { 1 } },
227 #ifndef INTERACTIVE
228 { "a?\\>(-|a)(-|a)\\b| ", "", "", "a-a-a", { 1, 1 } }, // boost has a partial match bug when interactive() blk=1 & does not check \> at start, so accepts more liberally
229 #endif
230 { "\\b(-|a)(-|a)\\bz?| ", "", "", "aa a-z", { 1, 2, 1 } },
231 { "(-|a)(-|a)\\bz?| ", "", "", "aa a-z", { 1, 2, 1 } },
232 { "a?\\b(-|a)(-|a)\\b| ", "", "", "a-a", { 1 } },
233 #ifndef INTERACTIVE
234 { "-(?=\\<a\\>)|-|a|b", "", "", "-a-ab", { 1, 3, 2, 3, 4 } }, // boost has a partial match bug when interactive() blk=1
235 #endif
236 // Unicode
237 { "(©)+", "", "", "©", { 1 } },
238 { NULL, NULL, NULL, NULL, { } }
239 };
240
main()241 int main()
242 {
243 banner("PATTERN TESTS");
244 for (const Test *test = tests; test->pattern != NULL; ++test)
245 {
246 std::string regex;
247 try
248 {
249 regex = BoostPosixMatcher::convert(test->pattern, convert_flag::recap);
250 }
251 catch (const regex_error& e)
252 {
253 std::cerr << e.what();
254 }
255 std::cout << regex << std::endl;
256 boost::regex pattern(regex);
257 BoostPosixMatcher matcher(pattern, test->cstring, test->mopts);
258 #ifdef INTERACTIVE
259 matcher.interactive(); // test with blk=1
260 #endif
261 printf("Test \"%s\" against \"%s\"\n", test->pattern, test->cstring);
262 if (*test->popts)
263 printf("With pattern options \"%s\"\n", test->popts);
264 if (*test->mopts)
265 printf("With matcher options \"%s\"\n", test->mopts);
266 size_t i = 0;
267 while (matcher.scan())
268 {
269 printf(" At %zu,%zu;[%zu,%zu]: \"%s\" matches pattern %zu\n", matcher.lineno(), matcher.columno(), matcher.first(), matcher.last(), matcher.text(), matcher.accept());
270 if (matcher.accept() != test->accepts[i])
271 break;
272 ++i;
273 }
274 if (matcher.accept() != 0 || test->accepts[i] != 0 || !matcher.at_end())
275 {
276 if (!matcher.at_end())
277 printf("ERROR: remaining input rest = '%s'\n", matcher.rest());
278 else
279 printf("ERROR: accept = %zu text = '%s'\n", matcher.accept(), matcher.text());
280 exit(1);
281 }
282 printf("OK\n\n");
283 }
284 BoostPosixMatcher pattern1("(\\w+)|(\\W)");
285 BoostPosixMatcher pattern2("\\<.*\\>");
286 BoostPosixMatcher pattern3(" ");
287 BoostPosixMatcher pattern4("[ \\t]+");
288 BoostPosixMatcher pattern5("\\b");
289 BoostPosixMatcher pattern6("");
290 BoostPosixMatcher pattern7("[[:alpha:]]");
291 BoostPosixMatcher pattern8("\\w+");
292 BoostPosixMatcher pattern9(BoostPosixMatcher::convert("(?u:\\p{L})"));
293
294 BoostPosixMatcher matcher(pattern1);
295 std::string test;
296 //
297 banner("TEST FIND");
298 //
299 matcher.pattern(pattern8);
300 matcher.input("an apple a day");
301 test = "";
302 while (matcher.find())
303 {
304 std::cout << matcher.text() << "/";
305 test.append(matcher.text()).append("/");
306 }
307 std::cout << std::endl;
308 if (test != "an/apple/a/day/")
309 error("find results");
310 //
311 matcher.pattern(pattern5);
312 matcher.reset("N");
313 matcher.input("a a");
314 test = "";
315 while (matcher.find())
316 {
317 std::cout << matcher.text() << "/";
318 test.append(matcher.text()).append("/");
319 }
320 std::cout << std::endl;
321 if (test != "///")
322 error("find with nullable results");
323 matcher.reset("");
324 //
325 matcher.pattern(pattern6);
326 matcher.reset("N");
327 matcher.input("a a");
328 test = "";
329 while (matcher.find())
330 {
331 std::cout << matcher.text() << "/";
332 test.append(matcher.text()).append("/");
333 }
334 std::cout << std::endl;
335 if (test != "///")
336 error("find with nullable results");
337 matcher.reset("");
338 //
339 banner("TEST SPLIT");
340 //
341 matcher.pattern(pattern3);
342 matcher.input("ab c d");
343 test = "";
344 while (matcher.split())
345 {
346 std::cout << matcher.text() << "/";
347 test.append(matcher.text()).append("/");
348 }
349 std::cout << std::endl;
350 if (test != "ab/c//d/")
351 error("split results");
352 //
353 matcher.pattern(pattern3);
354 matcher.input("ab c d ");
355 test = "";
356 while (matcher.split())
357 {
358 std::cout << matcher.text() << "/";
359 test.append(matcher.text()).append("/");
360 }
361 std::cout << std::endl;
362 if (test != "ab/c//d//")
363 error("split results");
364 //
365 matcher.pattern(pattern4);
366 matcher.input("ab c d");
367 test = "";
368 while (matcher.split())
369 {
370 std::cout << matcher.text() << "/";
371 test.append(matcher.text()).append("/");
372 }
373 std::cout << std::endl;
374 if (test != "ab/c/d/")
375 error("split results");
376 //
377 matcher.pattern(pattern5);
378 matcher.input("ab c d");
379 test = "";
380 while (matcher.split())
381 {
382 std::cout << matcher.text() << "/";
383 test.append(matcher.text()).append("/");
384 }
385 std::cout << std::endl;
386 if (test != "/ab/ /c/ /d//")
387 error("split results");
388 //
389 matcher.pattern(pattern6);
390 matcher.input("ab c d");
391 test = "";
392 while (matcher.split())
393 {
394 std::cout << matcher.text() << "/";
395 test.append(matcher.text()).append("/");
396 }
397 std::cout << std::endl;
398 if (test != "/a/b/ /c/ / /d//")
399 error("split results");
400 //
401 matcher.pattern(pattern6);
402 matcher.input("");
403 test = "";
404 while (matcher.split())
405 {
406 std::cout << matcher.text() << "/";
407 test.append(matcher.text()).append("/");
408 }
409 std::cout << std::endl;
410 if (test != "/")
411 error("split results");
412 //
413 matcher.pattern(pattern7);
414 matcher.input("a-b");
415 test = "";
416 while (matcher.split())
417 {
418 std::cout << matcher.text() << "/";
419 test.append(matcher.text()).append("/");
420 }
421 std::cout << std::endl;
422 if (test != "/-//")
423 error("split results");
424 //
425 matcher.pattern(pattern7);
426 matcher.input("a");
427 test = "";
428 while (matcher.split())
429 {
430 std::cout << matcher.text() << "/";
431 test.append(matcher.text()).append("/");
432 }
433 std::cout << std::endl;
434 if (test != "//")
435 error("split results");
436 //
437 matcher.pattern(pattern7);
438 matcher.input("-");
439 test = "";
440 while (matcher.split())
441 {
442 std::cout << matcher.text() << "/";
443 test.append(matcher.text()).append("/");
444 }
445 std::cout << std::endl;
446 if (test != "-/")
447 error("split results");
448 //
449 matcher.pattern(pattern4);
450 matcher.input("ab c d");
451 int n = 2; // split 2
452 while (n-- && matcher.split())
453 std::cout << matcher.text() << "/";
454 std::cout << std::endl << "REST = " << matcher.rest() << std::endl;
455 //
456 banner("TEST INPUT/UNPUT");
457 //
458 matcher.pattern(pattern2);
459 matcher.input("ab c d");
460 while (!matcher.at_end())
461 std::cout << (char)matcher.input() << "/";
462 std::cout << std::endl;
463 //
464 matcher.pattern(pattern2);
465 matcher.input("ab c d");
466 test = "";
467 while (true)
468 {
469 if (matcher.scan())
470 {
471 std::cout << matcher.text() << "/";
472 test.append(matcher.text()).append("/");
473 }
474 else if (!matcher.at_end())
475 {
476 std::cout << (char)matcher.input() << "?/";
477 test.append("?/");
478 }
479 else
480 {
481 break;
482 }
483 }
484 std::cout << std::endl;
485 if (test != "ab c d/")
486 error("input");
487 //
488 matcher.pattern(pattern7);
489 matcher.input("ab c d");
490 test = "";
491 while (true)
492 {
493 if (matcher.scan())
494 {
495 std::cout << matcher.text() << "/";
496 test.append(matcher.text()).append("/");
497 }
498 else if (!matcher.at_end())
499 {
500 std::cout << (char)matcher.input() << "?/";
501 test.append("?/");
502 }
503 else
504 {
505 break;
506 }
507 }
508 std::cout << std::endl;
509 if (test != "a/b/?/c/?/?/d/")
510 error("input");
511 //
512 matcher.pattern(pattern7);
513 matcher.input("ab c d");
514 matcher.unput('a');
515 test = "";
516 while (true)
517 {
518 if (matcher.scan())
519 {
520 std::cout << matcher.text() << "/";
521 test.append(matcher.text()).append("/");
522 if (*matcher.text() == 'b')
523 matcher.unput('c');
524 }
525 else if (!matcher.at_end())
526 {
527 std::cout << (char)matcher.input() << "?/";
528 }
529 else
530 {
531 break;
532 }
533 }
534 std::cout << std::endl;
535 if (test != "a/a/b/c/c/d/")
536 error("unput");
537 //
538 matcher.pattern(pattern9);
539 matcher.input("ab c d");
540 matcher.wunput(L'ä');
541 test = "";
542 while (true)
543 {
544 if (matcher.scan())
545 {
546 std::cout << matcher.text() << "/";
547 test.append(matcher.text()).append("/");
548 if (*matcher.text() == 'b')
549 matcher.wunput(L'ç');
550 }
551 else if (!matcher.at_end())
552 {
553 std::cout << (char)matcher.winput() << "?/";
554 }
555 else
556 {
557 break;
558 }
559 }
560 std::cout << std::endl;
561 if (test != "ä/a/b/ç/c/d/")
562 error("wunput");
563 //
564 banner("TEST WRAP");
565 //
566 WrappedMatcher wrapped_matcher;
567 wrapped_matcher.pattern(pattern8);
568 test = "";
569 while (wrapped_matcher.find())
570 {
571 std::cout << wrapped_matcher.text() << "/";
572 test.append(wrapped_matcher.text()).append("/");
573 }
574 std::cout << std::endl;
575 if (test != "Hello/World/How/now/brown/cow/An/apple/a/day/")
576 error("wrap");
577 //
578 banner("TEST REST");
579 //
580 matcher.pattern(pattern8);
581 matcher.input("abc def xyz");
582 test = "";
583 if (matcher.find())
584 {
585 std::cout << matcher.text() << "/";
586 test.append(matcher.text()).append("/");
587 }
588 std::cout << std::endl;
589 if (test != "abc/" || strcmp(matcher.rest(), " def xyz") != 0)
590 error("rest");
591 //
592 banner("TEST SKIP");
593 //
594 matcher.pattern(pattern8);
595 matcher.input("abc \ndef xyz");
596 test = "";
597 if (matcher.scan())
598 {
599 std::cout << matcher.text() << "/";
600 test.append(matcher.text()).append("/");
601 matcher.skip('\n');
602 }
603 if (matcher.scan())
604 {
605 std::cout << matcher.text() << "/";
606 test.append(matcher.text()).append("/");
607 matcher.skip('\n');
608 }
609 //
610 matcher.input("abc ¶def¶");
611 test = "";
612 if (matcher.scan())
613 {
614 std::cout << matcher.text() << "/";
615 test.append(matcher.text()).append("/");
616 matcher.skip(L'¶');
617 }
618 if (matcher.scan())
619 {
620 std::cout << matcher.text() << "/";
621 test.append(matcher.text()).append("/");
622 matcher.skip(L'¶');
623 }
624 //
625 matcher.input("abc xxydef xx");
626 test = "";
627 if (matcher.scan())
628 {
629 std::cout << matcher.text() << "/";
630 test.append(matcher.text()).append("/");
631 matcher.skip("xy");
632 }
633 if (matcher.scan())
634 {
635 std::cout << matcher.text() << "/";
636 test.append(matcher.text()).append("/");
637 matcher.skip("xy");
638 }
639 std::cout << std::endl;
640 if (test != "abc/def/")
641 error("skip");
642 //
643 #ifdef WITH_SPAN
644 banner("TEST SPAN");
645 //
646 matcher.pattern(pattern8);
647 matcher.input("##a#b#c##\ndef##\n##ghi\n##xyz");
648 test = "";
649 while (matcher.find())
650 {
651 std::cout << matcher.span() << "/";
652 test.append(matcher.span()).append("/");
653 }
654 std::cout << std::endl;
655 if (test != "##a#b#c##/def##/##ghi/##xyz/")
656 error("span");
657 //
658 banner("TEST LINE");
659 //
660 matcher.pattern(pattern8);
661 matcher.input("##a#b#c##\ndef##\n##ghi\n##xyz");
662 test = "";
663 while (matcher.find())
664 {
665 std::cout << matcher.line() << "/";
666 test.append(matcher.line()).append("/");
667 }
668 std::cout << std::endl;
669 if (test != "##a#b#c##/##a#b#c##/##a#b#c##/def##/##ghi/##xyz/")
670 error("line");
671 #endif
672 //
673 banner("TEST MORE");
674 //
675 matcher.pattern(pattern7);
676 matcher.input("abc");
677 test = "";
678 while (matcher.scan())
679 {
680 std::cout << matcher.text() << "/";
681 matcher.more();
682 test.append(matcher.text()).append("/");
683 }
684 std::cout << std::endl;
685 if (test != "a/ab/abc/")
686 error("more");
687 //
688 banner("TEST LESS");
689 //
690 matcher.pattern(pattern1);
691 matcher.input("abc");
692 test = "";
693 while (matcher.scan())
694 {
695 matcher.less(1);
696 std::cout << matcher.text() << "/";
697 test.append(matcher.text()).append("/");
698 }
699 std::cout << std::endl;
700 if (test != "a/b/c/")
701 error("less");
702 //
703 banner("TEST MATCHES");
704 //
705 if (BoostPosixMatcher("\\w+", "hello").matches()) // on the fly string matching
706 std::cout << "OK";
707 else
708 error("match results");
709 std::cout << std::endl;
710 if (BoostPosixMatcher("\\d", "0").matches())
711 std::cout << "OK";
712 else
713 error("match results");
714 std::cout << std::endl;
715 //
716 matcher.pattern(pattern1);
717 matcher.input("abc");
718 if (matcher.matches())
719 std::cout << "OK";
720 else
721 error("match results");
722 std::cout << std::endl;
723 //
724 matcher.pattern(pattern2);
725 matcher.input("abc");
726 if (matcher.matches())
727 std::cout << "OK";
728 else
729 error("match results");
730 std::cout << std::endl;
731 //
732 matcher.pattern(pattern6);
733 matcher.input("");
734 if (matcher.matches())
735 std::cout << "OK";
736 else
737 error("match results");
738 std::cout << std::endl;
739 //
740 matcher.pattern(pattern2);
741 matcher.input("---");
742 if (!matcher.matches())
743 std::cout << "OK";
744 else
745 error("match results");
746 std::cout << std::endl;
747 //
748 banner("DONE");
749 //
750 return 0;
751 }
752