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;
45 test_random (unsigned int rx_length, unsigned int max_str_len, unsigned int str_count)
49 char rand_rx[rx_length+1];
50 char matching_str[str_count][max_str_len+1];
58 struct GNUNET_REGEX_Automaton *dfa;
60 regmatch_t matchptr[1];
65 // At least one string is needed for matching
66 GNUNET_assert (str_count > 0);
67 // The string should be at least as long as the regex itself
68 GNUNET_assert (max_str_len >= rx_length);
71 matching_strp = matching_str[0];
73 // Generate random regex and a string that matches the regex
74 for (i=0; i<rx_length; i++)
76 char_op_switch = 0 + (int)(1.0 * rand() / (RAND_MAX + 1.0));
77 char_offset = (rand()%2) ? 65 : 97;
79 if (0 == char_op_switch
97 current_char = (char)(char_offset + (int)( 25.0 * rand() / (RAND_MAX + 1.0)));
103 current_char = (char)(char_offset + (int)( 25.0 * rand() / (RAND_MAX + 1.0)));
107 if (current_char != '+'
108 && current_char != '*'
109 && current_char != '|')
111 *matching_strp = current_char;
115 *rand_rxp = current_char;
119 *matching_strp = '\0';
123 for (i=0; i<str_count; i++)
125 // Match string using DFA
126 dfa = GNUNET_REGEX_construct_dfa (rand_rx, strlen (rand_rx));
129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constructing DFA failed\n");
133 eval = GNUNET_REGEX_eval (dfa, matching_str[i]);
134 GNUNET_REGEX_automaton_destroy (dfa);
136 // Match string using glibc regex
137 if (0 != regcomp (&rx, rand_rx, REG_EXTENDED))
139 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not compile regex using regcomp\n");
143 eval_check = regexec (&rx, matching_str[i], 1, matchptr, 0);
145 // We only want to match the whole string, because that's what our DFA does, too.
146 if (eval_check == 0 && (matchptr[0].rm_so != 0 || matchptr[0].rm_eo != strlen (matching_str[i])))
150 if (eval_check != eval)
152 regerror (eval_check, &rx, error, sizeof error);
153 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
154 "Unexpected result:\nregex: %s\nstring: %s\ngnunet regex: %i\nglibc regex: %i\nglibc error: %s\n\n",
155 rand_rx, matching_str, eval, eval_check, error);
163 test_automaton (struct GNUNET_REGEX_Automaton *a, regex_t *rx, struct Regex_String_Pair *rxstr)
173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Automaton was NULL\n");
179 for (i=0; i<rxstr->string_count; i++)
181 eval = GNUNET_REGEX_eval (a, rxstr->strings[i]);
182 eval_check = regexec (rx, rxstr->strings[i], 0, NULL, 0);
184 if ((rxstr->expected_results[i] == match
185 && (0 != eval || 0 != eval_check))
187 (rxstr->expected_results[i] == nomatch
188 && (0 == eval || 0 == eval_check)))
191 regerror (eval_check, rx, error, sizeof error);
192 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
193 "Unexpected result:\nregex: %s\nstring: %s\nexpected result: %i\ngnunet regex: %i\nglibc regex: %i\nglibc error: %s\n\n",
194 rxstr->regex, rxstr->strings[i], rxstr->expected_results[i], eval, eval_check, error);
201 main (int argc, char *argv[])
203 GNUNET_log_setup ("test-regex",
214 struct Regex_String_Pair rxstr[3];
215 struct GNUNET_REGEX_Automaton *a;
223 rxstr[0].regex = "ab(c|d)+c*(a(b|c)d)+";
224 rxstr[0].string_count = 5;
225 rxstr[0].strings = GNUNET_malloc (sizeof (char *) * rxstr[0].string_count);
226 rxstr[0].strings[0] = "abcdcdcdcdddddabd";
227 rxstr[0].strings[1] = "abcd";
228 rxstr[0].strings[2] = "abcddddddccccccccccccccccccccccccabdacdabd";
229 rxstr[0].strings[3] = "abccccca";
230 rxstr[0].strings[4] = "abcdcdcdccdabdabd";
231 rxstr[0].expected_results = GNUNET_malloc (sizeof (enum Match_Result) * rxstr[0].string_count);
232 rxstr[0].expected_results[0] = match;
233 rxstr[0].expected_results[1] = nomatch;
234 rxstr[0].expected_results[2] = match;
235 rxstr[0].expected_results[3] = nomatch;
236 rxstr[0].expected_results[4] = match;
240 if (0 != regcomp (&rx, rxstr->regex, REG_EXTENDED | REG_NOSUB))
242 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not compile regex using regcomp()\n");
247 a = GNUNET_REGEX_construct_nfa (rxstr[i].regex, strlen (rxstr[i].regex));
248 check_nfa += test_automaton (a, &rx, &rxstr[i]);
249 GNUNET_REGEX_automaton_destroy (a);
252 a = GNUNET_REGEX_construct_dfa (rxstr[i].regex, strlen (rxstr[i].regex));
253 check_dfa += test_automaton (a, &rx, &rxstr[i]);
254 GNUNET_REGEX_automaton_destroy (a);
260 for (i=0; i< 100; i++)
261 check_rand += test_random (100, 100, 1);
263 return check_nfa + check_dfa + check_rand;