• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdint.h>
4 #include <stdlib.h>
5 #include <string.h>
6 
7 #include "rure.h"
8 
9 #ifndef DEBUG
10   #define DEBUG false
11 #endif
12 
test_is_match()13 bool test_is_match() {
14     bool passed = true;
15     const char *haystack = "snowman: \xE2\x98\x83";
16 
17     rure *re = rure_compile_must("\\p{So}$");
18     bool matched = rure_is_match(re, (const uint8_t *)haystack,
19                                  strlen(haystack), 0);
20     if (!matched) {
21         if (DEBUG) {
22             fprintf(stderr,
23                     "[test_is_match] expected match, but got no match\n");
24         }
25         passed = false;
26     }
27     rure_free(re);
28     return passed;
29 }
30 
test_shortest_match()31 bool test_shortest_match() {
32     bool passed = true;
33     const char *haystack = "aaaaa";
34 
35     rure *re = rure_compile_must("a+");
36     size_t end = 0;
37     bool matched = rure_shortest_match(re, (const uint8_t *)haystack,
38                                        strlen(haystack), 0, &end);
39     if (!matched) {
40         if (DEBUG) {
41             fprintf(stderr,
42                     "[test_shortest_match] expected match, "
43                     "but got no match\n");
44         }
45         passed = false;
46     }
47     size_t expect_end = 1;
48     if (end != expect_end) {
49         if (DEBUG) {
50             fprintf(stderr,
51                     "[test_shortest_match] expected match end location %zu "
52                     "but got %zu\n", expect_end, end);
53         }
54         passed = false;
55     }
56     rure_free(re);
57     return passed;
58 }
59 
test_find()60 bool test_find() {
61     bool passed = true;
62     const char *haystack = "snowman: \xE2\x98\x83";
63 
64     rure *re = rure_compile_must("\\p{So}$");
65     rure_match match = {0};
66     bool matched = rure_find(re, (const uint8_t *)haystack, strlen(haystack),
67                              0, &match);
68     if (!matched) {
69         if (DEBUG) {
70             fprintf(stderr, "[test_find] expected match, but got no match\n");
71         }
72         passed = false;
73     }
74     size_t expect_start = 9;
75     size_t expect_end = 12;
76     if (match.start != expect_start || match.end != expect_end) {
77         if (DEBUG) {
78             fprintf(stderr,
79                     "[test_find] expected match at (%zu, %zu), but "
80                     "got match at (%zu, %zu)\n",
81                     expect_start, expect_end, match.start, match.end);
82         }
83         passed = false;
84     }
85     rure_free(re);
86     return passed;
87 }
88 
test_captures()89 bool test_captures() {
90     bool passed = true;
91     const char *haystack = "snowman: \xE2\x98\x83";
92 
93     rure *re = rure_compile_must(".(.*(?P<snowman>\\p{So}))$");
94     rure_match match = {0};
95     rure_captures *caps = rure_captures_new(re);
96     bool matched = rure_find_captures(re, (const uint8_t *)haystack,
97                                       strlen(haystack), 0, caps);
98     if (!matched) {
99         if (DEBUG) {
100             fprintf(stderr,
101                     "[test_captures] expected match, but got no match\n");
102         }
103         passed = false;
104     }
105     size_t expect_captures_len = 3;
106     size_t captures_len = rure_captures_len(caps);
107     if (captures_len != expect_captures_len) {
108         if (DEBUG) {
109             fprintf(stderr,
110                     "[test_captures] "
111                     "expected capture group length to be %zd, but "
112                     "got %zd\n",
113                     expect_captures_len, captures_len);
114         }
115         passed = false;
116         goto done;
117     }
118     int32_t expect_capture_index = 2;
119     int32_t capture_index = rure_capture_name_index(re, "snowman");
120     if (capture_index != expect_capture_index) {
121         if (DEBUG) {
122             fprintf(stderr,
123                     "[test_captures] "
124                     "expected capture index %d for name 'snowman', but "
125                     "got %d\n",
126                     expect_capture_index, capture_index);
127         }
128         passed = false;
129         goto done;
130     }
131     size_t expect_start = 9;
132     size_t expect_end = 12;
133     rure_captures_at(caps, 2, &match);
134     if (match.start != expect_start || match.end != expect_end) {
135         if (DEBUG) {
136             fprintf(stderr,
137                     "[test_captures] "
138                     "expected capture 2 match at (%zu, %zu), "
139                     "but got match at (%zu, %zu)\n",
140                     expect_start, expect_end, match.start, match.end);
141         }
142         passed = false;
143     }
144 done:
145     rure_captures_free(caps);
146     rure_free(re);
147     return passed;
148 }
149 
test_iter()150 bool test_iter() {
151     bool passed = true;
152     const uint8_t *haystack = (const uint8_t *)"abc xyz";
153     size_t haystack_len = strlen((const char *)haystack);
154 
155     rure *re = rure_compile_must("\\w+(\\w)");
156     rure_match match = {0};
157     rure_captures *caps = rure_captures_new(re);
158     rure_iter *it = rure_iter_new(re);
159 
160     bool matched = rure_iter_next(it, haystack, haystack_len, &match);
161     if (!matched) {
162         if (DEBUG) {
163             fprintf(stderr,
164                     "[test_iter] expected first match, but got no match\n");
165         }
166         passed = false;
167         goto done;
168     }
169     size_t expect_start = 0;
170     size_t expect_end = 3;
171     if (match.start != expect_start || match.end != expect_end) {
172         if (DEBUG) {
173             fprintf(stderr,
174                     "[test_iter] expected first match at (%zu, %zu), but "
175                     "got match at (%zu, %zu)\n",
176                     expect_start, expect_end, match.start, match.end);
177         }
178         passed = false;
179         goto done;
180     }
181 
182     matched = rure_iter_next_captures(it, haystack, haystack_len, caps);
183     if (!matched) {
184         if (DEBUG) {
185             fprintf(stderr,
186                     "[test_iter] expected second match, but got no match\n");
187         }
188         passed = false;
189         goto done;
190     }
191     rure_captures_at(caps, 1, &match);
192     expect_start = 6;
193     expect_end = 7;
194     if (match.start != expect_start || match.end != expect_end) {
195         if (DEBUG) {
196             fprintf(stderr,
197                     "[test_iter] expected second match at (%zu, %zu), but "
198                     "got match at (%zu, %zu)\n",
199                     expect_start, expect_end, match.start, match.end);
200         }
201         passed = false;
202         goto done;
203     }
204 done:
205     rure_iter_free(it);
206     rure_captures_free(caps);
207     rure_free(re);
208     return passed;
209 }
210 
test_iter_capture_name(char * expect,char * given)211 bool test_iter_capture_name(char *expect, char *given) {
212     bool passed = true;
213     if (strcmp(expect, given)) {
214         if (DEBUG) {
215             fprintf(stderr,
216                     "[test_iter_capture_name] expected first capture "
217                     "name '%s' got '%s'\n",
218                     expect, given);
219         }
220         passed = false;
221     }
222     return passed;
223 }
224 
test_iter_capture_names()225 bool test_iter_capture_names() {
226     bool passed = true;
227 
228     char *name;
229     rure *re = rure_compile_must(
230         "(?P<year>\\d{4})-(?P<month>\\d{2})-(?P<day>\\d{2})");
231     rure_iter_capture_names *it = rure_iter_capture_names_new(re);
232 
233     bool result = rure_iter_capture_names_next(it, &name);
234     if (!result) {
235         if (DEBUG) {
236             fprintf(stderr,
237                     "[test_iter_capture_names] expected a second name, "
238                     "but got none\n");
239         }
240         passed = false;
241         goto done;
242     }
243 
244     result = rure_iter_capture_names_next(it, &name);
245     passed = test_iter_capture_name("year", name);
246     if (!passed) {
247         goto done;
248     }
249 
250     result = rure_iter_capture_names_next(it, &name);
251     passed = test_iter_capture_name("month", name);
252     if (!passed) {
253         goto done;
254     }
255 
256     result = rure_iter_capture_names_next(it, &name);
257     passed = test_iter_capture_name("day", name);
258     if (!passed) {
259         goto done;
260     }
261 done:
262     rure_iter_capture_names_free(it);
263     rure_free(re);
264     return passed;
265 }
266 
267 /*
268  * This tests whether we can set the flags correctly. In this case, we disable
269  * all flags, which includes disabling Unicode mode. When we disable Unicode
270  * mode, we can match arbitrary possibly invalid UTF-8 bytes, such as \xFF.
271  * (When Unicode mode is enabled, \xFF won't match .)
272  */
test_flags()273 bool test_flags() {
274     bool passed = true;
275     const char *pattern = ".";
276     const char *haystack = "\xFF";
277 
278     rure *re = rure_compile((const uint8_t *)pattern, strlen(pattern),
279                             0, NULL, NULL);
280     bool matched = rure_is_match(re, (const uint8_t *)haystack,
281                                  strlen(haystack), 0);
282     if (!matched) {
283         if (DEBUG) {
284             fprintf(stderr, "[test_flags] expected match, but got no match\n");
285         }
286         passed = false;
287     }
288     rure_free(re);
289     return passed;
290 }
291 
test_compile_error()292 bool test_compile_error() {
293     bool passed = true;
294     rure_error *err = rure_error_new();
295     rure *re = rure_compile((const uint8_t *)"(", 1, 0, NULL, err);
296     if (re != NULL) {
297         if (DEBUG) {
298             fprintf(stderr,
299                     "[test_compile_error] "
300                     "expected NULL regex pointer, but got non-NULL pointer\n");
301         }
302         passed = false;
303         rure_free(re);
304     }
305     const char *msg = rure_error_message(err);
306     if (NULL == strstr(msg, "unclosed group")) {
307         if (DEBUG) {
308             fprintf(stderr,
309                     "[test_compile_error] "
310                     "expected an 'unclosed parenthesis' error message, but "
311                     "got this instead: '%s'\n", msg);
312         }
313         passed = false;
314     }
315     rure_error_free(err);
316     return passed;
317 }
318 
test_compile_error_size_limit()319 bool test_compile_error_size_limit() {
320     bool passed = true;
321     rure_options *opts = rure_options_new();
322     rure_options_size_limit(opts, 0);
323     rure_error *err = rure_error_new();
324     rure *re = rure_compile((const uint8_t *)"\\w{100}", 8, 0, opts, err);
325     if (re != NULL) {
326         if (DEBUG) {
327             fprintf(stderr,
328                     "[test_compile_error_size_limit] "
329                     "expected NULL regex pointer, but got non-NULL pointer\n");
330         }
331         passed = false;
332         rure_free(re);
333     }
334     const char *msg = rure_error_message(err);
335     if (NULL == strstr(msg, "exceeds size")) {
336         if (DEBUG) {
337             fprintf(stderr,
338                     "[test_compile_error] "
339                     "expected an 'exceeds size' error message, but "
340                     "got this instead: '%s'\n", msg);
341         }
342         passed = false;
343     }
344     rure_options_free(opts);
345     rure_error_free(err);
346     return passed;
347 }
348 
test_regex_set_matches()349 bool test_regex_set_matches() {
350 
351 #define PAT_COUNT 6
352 
353     bool passed = true;
354     const char *patterns[] = {
355         "foo", "barfoo", "\\w+", "\\d+", "foobar", "bar"
356     };
357     const size_t patterns_lengths[] = {
358         3, 6, 3, 3, 6, 3
359     };
360 
361     rure_error *err = rure_error_new();
362     rure_set *re = rure_compile_set((const uint8_t **) patterns,
363                                     patterns_lengths,
364                                     PAT_COUNT,
365                                     0,
366                                     NULL,
367                                     err);
368     if (re == NULL) {
369         passed = false;
370         goto done2;
371     }
372 
373     if (rure_set_len(re) != PAT_COUNT) {
374         passed = false;
375         goto done1;
376     }
377 
378     if (!rure_set_is_match(re, (const uint8_t *) "foobar", 6, 0)) {
379         passed = false;
380         goto done1;
381     }
382 
383     if (rure_set_is_match(re, (const uint8_t *) "", 0, 0)) {
384         passed = false;
385         goto done1;
386     }
387 
388     bool matches[PAT_COUNT];
389     if (!rure_set_matches(re, (const uint8_t *) "foobar", 6, 0, matches)) {
390         passed = false;
391         goto done1;
392     }
393 
394     const bool match_target[] = {
395         true, false, true, false, true, true
396     };
397 
398     int i;
399     for (i = 0; i < PAT_COUNT; ++i) {
400         if (matches[i] != match_target[i]) {
401             passed = false;
402             goto done1;
403         }
404     }
405 
406 done1:
407     rure_set_free(re);
408 done2:
409     rure_error_free(err);
410     return passed;
411 
412 #undef PAT_COUNT
413 }
414 
test_regex_set_match_start()415 bool test_regex_set_match_start() {
416 
417 #define PAT_COUNT 3
418 
419     bool passed = true;
420     const char *patterns[] = {
421         "foo", "bar", "fooo"
422     };
423     const size_t patterns_lengths[] = {
424         3, 3, 4
425     };
426 
427     rure_error *err = rure_error_new();
428     rure_set *re = rure_compile_set((const uint8_t **) patterns,
429                                     patterns_lengths,
430                                     PAT_COUNT,
431                                     0,
432                                     NULL,
433                                     err);
434     if (re == NULL) {
435         passed = false;
436         goto done2;
437     }
438 
439     if (rure_set_len(re) != PAT_COUNT) {
440         passed = false;
441         goto done1;
442     }
443 
444     if (rure_set_is_match(re, (const uint8_t *)"foobiasdr", 7, 2)) {
445         passed = false;
446         goto done1;
447     }
448 
449     {
450         bool matches[PAT_COUNT];
451         if (!rure_set_matches(re, (const uint8_t *)"fooobar", 8, 0, matches)) {
452             passed = false;
453             goto done1;
454         }
455 
456         const bool match_target[] = {
457             true, true, true
458         };
459 
460         int i;
461         for (i = 0; i < PAT_COUNT; ++i) {
462             if (matches[i] != match_target[i]) {
463                 passed = false;
464                 goto done1;
465             }
466         }
467     }
468 
469     {
470         bool matches[PAT_COUNT];
471         if (!rure_set_matches(re, (const uint8_t *)"fooobar", 7, 1, matches)) {
472             passed = false;
473             goto done1;
474         }
475 
476         const bool match_target[] = {
477             false, true, false
478         };
479 
480         int i;
481         for (i = 0; i < PAT_COUNT; ++i) {
482             if (matches[i] != match_target[i]) {
483                 passed = false;
484                 goto done1;
485             }
486         }
487     }
488 
489 done1:
490     rure_set_free(re);
491 done2:
492     rure_error_free(err);
493     return passed;
494 
495 #undef PAT_COUNT
496 }
497 
test_regex_set_options()498 bool test_regex_set_options() {
499 
500     bool passed = true;
501     rure_options *opts = rure_options_new();
502     rure_options_size_limit(opts, 0);
503     rure_error *err = rure_error_new();
504 
505     const char *patterns[] = { "\\w{100}" };
506     const size_t patterns_lengths[] = { 8 };
507 
508     rure_set *re = rure_compile_set(
509         (const uint8_t **) patterns, patterns_lengths, 1, 0, opts, err);
510     if (re != NULL) {
511         if (DEBUG) {
512             fprintf(stderr,
513                     "[test_compile_error_size_limit] "
514                     "expected NULL regex pointer, but got non-NULL pointer\n");
515         }
516         passed = false;
517         rure_set_free(re);
518     }
519     const char *msg = rure_error_message(err);
520     if (NULL == strstr(msg, "exceeds size")) {
521         if (DEBUG) {
522             fprintf(stderr,
523                     "[test_compile_error] "
524                     "expected an 'exceeds size' error message, but "
525                     "got this instead: '%s'\n", msg);
526         }
527         passed = false;
528     }
529     rure_options_free(opts);
530     rure_error_free(err);
531     return passed;
532 }
533 
test_escape()534 bool test_escape() {
535     bool passed = true;
536 
537     const char *pattern = "^[a-z]+.*$";
538     const char *expected_escaped = "\\^\\[a\\-z\\]\\+\\.\\*\\$";
539 
540     const char *escaped = rure_escape_must(pattern);
541     if (!escaped) {
542         if (DEBUG) {
543             fprintf(stderr,
544                     "[test_captures] expected escaped, but got no escaped\n");
545         }
546         passed = false;
547     } else if (strcmp(escaped, expected_escaped) != 0) {
548         if (DEBUG) {
549             fprintf(stderr,
550                     "[test_captures] expected \"%s\", but got \"%s\"\n",
551                     expected_escaped, escaped);
552         }
553         passed = false;
554     }
555     rure_cstring_free((char *) escaped);
556     return passed;
557 }
558 
run_test(bool (test)(),const char * name,bool * passed)559 void run_test(bool (test)(), const char *name, bool *passed) {
560     if (!test()) {
561         *passed = false;
562         fprintf(stderr, "FAILED: %s\n", name);
563     } else {
564         fprintf(stderr, "PASSED: %s\n", name);
565     }
566 }
567 
main()568 int main() {
569     bool passed = true;
570 
571     run_test(test_is_match, "test_is_match", &passed);
572     run_test(test_shortest_match, "test_shortest_match", &passed);
573     run_test(test_find, "test_find", &passed);
574     run_test(test_captures, "test_captures", &passed);
575     run_test(test_iter, "test_iter", &passed);
576     run_test(test_iter_capture_names, "test_iter_capture_names", &passed);
577     run_test(test_flags, "test_flags", &passed);
578     run_test(test_compile_error, "test_compile_error", &passed);
579     run_test(test_compile_error_size_limit, "test_compile_error_size_limit",
580              &passed);
581     run_test(test_regex_set_matches, "test_regex_set_match", &passed);
582     run_test(test_regex_set_options, "test_regex_set_options", &passed);
583     run_test(test_regex_set_match_start, "test_regex_set_match_start",
584              &passed);
585     run_test(test_escape, "test_escape", &passed);
586 
587     if (!passed) {
588         exit(1);
589     }
590     return 0;
591 }
592