2 This file is part of GNUnet
3 (C) 2012 Christian Grothoff (and other contributing authors)
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
21 * @file regex/test_regex.c
22 * @brief test for regex.c
23 * @author Maximilian Szengel
28 #include "gnunet_regex_lib.h"
36 struct Regex_String_Pair
41 enum Match_Result expected_results[20];
44 static const char allowed_literals[] =
46 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
47 "abcdefghijklmnopqrstuvwxyz";
50 test_random (unsigned int rx_length, unsigned int max_str_len, unsigned int str_count)
55 char rand_rx[rx_length+1];
56 char matching_str[str_count][max_str_len+1];
64 struct GNUNET_REGEX_Automaton *dfa;
66 regmatch_t matchptr[1];
71 // At least one string is needed for matching
72 GNUNET_assert (str_count > 0);
73 // The string should be at least as long as the regex itself
74 GNUNET_assert (max_str_len >= rx_length);
77 matching_strp = matching_str[0];
79 // Generate random regex and a string that matches the regex
80 for (i=0; i<rx_length; i++)
82 char_op_switch = 0 + (int)(1.0 * rand() / (RAND_MAX + 1.0));
84 if (0 == char_op_switch
99 if (i < rx_length -1) // '|' cannot be at the end
102 current_char = allowed_literals[rand() % (sizeof(allowed_literals) - 1)];
108 current_char = allowed_literals[rand() % (sizeof(allowed_literals) - 1)];
112 if (current_char != '+'
113 && current_char != '*'
114 && current_char != '|')
116 *matching_strp = current_char;
120 *rand_rxp = current_char;
124 *matching_strp = '\0';
126 // Generate some random strings for matching...
127 // Start at 1, because the first string is generated above during regex generation
128 for (i=1; i<str_count; i++)
130 str_len = rand() % max_str_len;
131 for (j=0; j<str_len; j++)
132 matching_str[i][j] = allowed_literals[rand() % (sizeof(allowed_literals) - 1)];
133 matching_str[i][str_len] = '\0';
138 for (i=0; i<str_count; i++)
140 // Match string using DFA
141 dfa = GNUNET_REGEX_construct_dfa (rand_rx, strlen (rand_rx));
144 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constructing DFA failed\n");
148 eval = GNUNET_REGEX_eval (dfa, matching_str[i]);
149 GNUNET_REGEX_automaton_destroy (dfa);
151 // Match string using glibc regex
152 if (0 != regcomp (&rx, rand_rx, REG_EXTENDED))
154 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not compile regex using regcomp\n");
158 eval_check = regexec (&rx, matching_str[i], 1, matchptr, 0);
160 // We only want to match the whole string, because that's what our DFA does, too.
161 if (eval_check == 0 && (matchptr[0].rm_so != 0 || matchptr[0].rm_eo != strlen (matching_str[i])))
165 if (eval_check != eval)
167 regerror (eval_check, &rx, error, sizeof error);
168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
169 "Unexpected result:\nregex: %s\nstring: %s\ngnunet regex: %i\nglibc regex: %i\nglibc error: %s\n\n",
170 rand_rx, matching_str, eval, eval_check, error);
178 test_automaton (struct GNUNET_REGEX_Automaton *a, regex_t *rx, struct Regex_String_Pair *rxstr)
184 regmatch_t matchptr[1];
189 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Automaton was NULL\n");
195 for (i=0; i<rxstr->string_count; i++)
197 eval = GNUNET_REGEX_eval (a, rxstr->strings[i]);
198 eval_check = regexec (rx, rxstr->strings[i], 1, matchptr, 0);
200 // We only want to match the whole string, because that's what our DFA does, too.
201 if (eval_check == 0 && (matchptr[0].rm_so != 0 || matchptr[0].rm_eo != strlen (rxstr->strings[i])))
204 if ((rxstr->expected_results[i] == match
205 && (0 != eval || 0 != eval_check))
207 (rxstr->expected_results[i] == nomatch
208 && (0 == eval || 0 == eval_check)))
211 regerror (eval_check, rx, error, sizeof error);
212 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
213 "Unexpected result:\nregex: %s\nstring: %s\nexpected result: %i\ngnunet regex: %i\nglibc regex: %i\nglibc error: %s\nrm_so: %i\nrm_eo: %i\n\n",
214 rxstr->regex, rxstr->strings[i], rxstr->expected_results[i], eval, eval_check, error, matchptr[0].rm_so, matchptr[0].rm_eo);
221 main (int argc, char *argv[])
223 GNUNET_log_setup ("test-regex",
234 struct Regex_String_Pair rxstr[2] = {
235 {"ab(c|d)+c*(a(b|c)d)+", 5,
236 {"abcdcdcdcdddddabd", "abcd", "abcddddddccccccccccccccccccccccccabdacdabd", "abccccca", "abcdcdcdccdabdabd"},
237 {match, nomatch, match, nomatch, match}},
238 {"ab+c*(a(bx|c)d)+", 5,
239 {"abcdcdcdcdddddabd", "abcd", "abcddddddccccccccccccccccccccccccabdacdabd", "abccccca", "abcdcdcdccdabdabd"},
240 {nomatch, nomatch, nomatch, nomatch, nomatch}}};
241 struct GNUNET_REGEX_Automaton *a;
251 if (0 != regcomp (&rx, rxstr[i].regex, REG_EXTENDED))
253 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not compile regex using regcomp()\n");
258 a = GNUNET_REGEX_construct_nfa (rxstr[i].regex, strlen (rxstr[i].regex));
259 check_nfa += test_automaton (a, &rx, &rxstr[i]);
260 GNUNET_REGEX_automaton_destroy (a);
263 a = GNUNET_REGEX_construct_dfa (rxstr[i].regex, strlen (rxstr[i].regex));
264 check_dfa += test_automaton (a, &rx, &rxstr[i]);
265 GNUNET_REGEX_automaton_destroy (a);
271 for (i=0; i< 100; i++)
272 check_rand += test_random (100, 100, 10);
274 return check_nfa + check_dfa + check_rand;