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