8dce076158a825f9971eb13c8bd5f2a4b3e17a08
[oweals/gnunet.git] / src / regex / test_regex_iterate_api.c
1 /*
2      This file is part of GNUnet
3      (C) 2012 Christian Grothoff (and other contributing authors)
4
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.
9
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.
14
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.
19 */
20 /**
21  * @file regex/test_regex_iterate_api.c
22  * @brief test for regex.c
23  * @author Maximilian Szengel
24  */
25 #include <regex.h>
26 #include <time.h>
27 #include "platform.h"
28 #include "gnunet_regex_lib.h"
29 #include "regex_internal.h"
30
31 #define GNUNET_REGEX_ITERATE_SAVE_DEBUG_GRAPH GNUNET_NO
32
33 static unsigned int transition_counter;
34
35 struct IteratorContext
36 {
37   int error;
38   int should_save_graph;
39   FILE *graph_filep;
40   unsigned int string_count;
41   char *const *strings;
42   unsigned int match_count;
43 };
44
45 struct RegexStringPair
46 {
47   char *regex;
48   unsigned int string_count;
49   char *strings[20];
50 };
51
52 void
53 key_iterator (void *cls, const struct GNUNET_HashCode *key, const char *proof,
54               int accepting, unsigned int num_edges,
55               const struct GNUNET_REGEX_Edge *edges)
56 {
57   unsigned int i;
58   struct IteratorContext *ctx = cls;
59   char *out_str;
60   char *state_id = GNUNET_strdup (GNUNET_h2s (key));
61
62   if (GNUNET_YES == ctx->should_save_graph)
63   {
64     if (GNUNET_YES == accepting)
65       GNUNET_asprintf (&out_str, "\"%s\" [shape=doublecircle]\n", state_id);
66     else
67       GNUNET_asprintf (&out_str, "\"%s\" [shape=circle]\n", state_id);
68     fwrite (out_str, strlen (out_str), 1, ctx->graph_filep);
69     GNUNET_free (out_str);
70
71     for (i = 0; i < num_edges; i++)
72     {
73       transition_counter++;
74       GNUNET_asprintf (&out_str, "\"%s\" -> \"%s\" [label = \"%s (%s)\"]\n",
75                        state_id, GNUNET_h2s (&edges[i].destination),
76                        edges[i].label, proof);
77       fwrite (out_str, strlen (out_str), 1, ctx->graph_filep);
78
79       GNUNET_free (out_str);
80     }
81   }
82   else
83   {
84     for (i = 0; i < num_edges; i++)
85       transition_counter++;
86   }
87
88   for (i = 0; i < ctx->string_count; i++)
89   {
90     if (0 == strcmp (proof, ctx->strings[i]))
91       ctx->match_count++;
92   }
93
94   if (GNUNET_OK != GNUNET_REGEX_check_proof (proof, key))
95   {
96     ctx->error++;
97     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
98                 "Proof check failed: proof: %s key: %s\n", proof, state_id);
99   }
100
101   GNUNET_free (state_id);
102 }
103
104 int
105 main (int argc, char *argv[])
106 {
107   GNUNET_log_setup ("test-regex", "WARNING", NULL);
108
109   int error;
110   struct GNUNET_REGEX_Automaton *dfa;
111   unsigned int i;
112   unsigned int num_transitions;
113   char *filename = NULL;
114   struct IteratorContext ctx = { 0, 0, NULL, 0, NULL, 0 };
115
116   error = 0;
117
118   const struct RegexStringPair rxstr[14] = {
119     {"ab(c|d)+c*(a(b|c)+d)+(bla)+", 2, {"abcdcdca", "abcabdbl"}},
120     {"abcdefghijklmnop*qst", 1, {"abcdefgh"}},
121     {"VPN-4-1(0|1)*", 2, {"VPN-4-10", "VPN-4-11"}},
122     {"a+X*y+c|p|R|Z*K*y*R+w|Y*6+n+h*k*w+V*F|W*B*e*", 4,
123      {"aaaaaaaa", "aaXXyyyc", "p", "Y"}},
124     {"a*", 8,
125      {"a", "aa", "aaa", "aaaa", "aaaaa", "aaaaaa", "aaaaaaa", "aaaaaaaa"}},
126     {"xzxzxzxzxz", 1, {"xzxzxzxz"}},
127     {"xyz*", 2, {"xy", "xyz"}},
128     {"ab", 1, {"a"}},
129     {"abcd:(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1):(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)(0|1)", 2, {"abcd:000", "abcd:101"}},
130     {"x*|(0|1|2)(a|b|c|d)", 2, {"xxxxxxxx", "0a"}},
131     {"(0|1)(0|1)23456789ABC", 1, {"11234567"}},
132     {"0*123456789ABC*", 3, {"00123456", "00000000", "12345678"}},
133     {"0123456789A*BC", 1, {"01234567"}},
134     {"GNUNETVPN000100000IPEX6-fc5a:4e1:c2ba::1", 1, {"GNUNETVP"}}
135   };
136
137   const char *graph_start_str = "digraph G {\nrankdir=LR\n";
138   const char *graph_end_str = "\n}\n";
139
140   for (i = 0; i < 14; i++)
141   {
142     // Create graph
143     if (GNUNET_YES == GNUNET_REGEX_ITERATE_SAVE_DEBUG_GRAPH)
144     {
145       GNUNET_asprintf (&filename, "iteration_graph_%u.dot", i);
146       ctx.graph_filep = fopen (filename, "w");
147       if (NULL == ctx.graph_filep)
148       {
149         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
150                     "Could not open file %s for saving iteration graph.\n",
151                     filename);
152         ctx.should_save_graph = GNUNET_NO;
153       }
154       else
155       {
156         ctx.should_save_graph = GNUNET_YES;
157         fwrite (graph_start_str, strlen (graph_start_str), 1, ctx.graph_filep);
158       }
159       GNUNET_free (filename);
160     }
161     else
162     {
163       ctx.should_save_graph = GNUNET_NO;
164       ctx.graph_filep = NULL;
165     }
166
167     // Iterate over DFA edges
168     transition_counter = 0;
169     ctx.string_count = rxstr[i].string_count;
170     ctx.strings = rxstr[i].strings;
171     ctx.match_count = 0;
172     dfa = GNUNET_REGEX_construct_dfa (rxstr[i].regex, strlen (rxstr[i].regex));
173     GNUNET_REGEX_iterate_all_edges (dfa, key_iterator, &ctx);
174     num_transitions = GNUNET_REGEX_get_transition_count (dfa);
175
176     if (transition_counter < num_transitions)
177     {
178       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
179                   "Automaton has %d transitions, iterated over %d transitions\n",
180                   num_transitions, transition_counter);
181       error += 1;
182       break;
183     }
184
185     if (ctx.match_count < ctx.string_count)
186     {
187       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
188                   "Missing initial states for regex %s\n", rxstr[i].regex);
189       error += (ctx.string_count - ctx.match_count);
190     }
191     else if (ctx.match_count > ctx.string_count)
192     {
193       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
194                   "Duplicate initial transitions for regex %s\n",
195                   rxstr[i].regex);
196       error += (ctx.string_count - ctx.match_count);
197     }
198
199     GNUNET_REGEX_automaton_destroy (dfa);
200
201     // Finish graph
202     if (GNUNET_YES == ctx.should_save_graph)
203     {
204       fwrite (graph_end_str, strlen (graph_end_str), 1, ctx.graph_filep);
205       fclose (ctx.graph_filep);
206       ctx.graph_filep = NULL;
207       ctx.should_save_graph = GNUNET_NO;
208     }
209   }
210
211
212   for (i = 0; i < 10; i++)
213   {
214     ctx.string_count = rxstr[i].string_count;
215     ctx.strings = rxstr[i].strings;
216     ctx.match_count = 0;
217
218     dfa = GNUNET_REGEX_construct_dfa (rxstr[i].regex, strlen (rxstr[i].regex));
219     GNUNET_REGEX_dfa_add_multi_strides (NULL, dfa, 2);
220     GNUNET_REGEX_iterate_all_edges (dfa, key_iterator, &ctx);
221
222     if (ctx.match_count < ctx.string_count)
223     {
224       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
225                   "Missing initial states for regex %s\n", rxstr[i].regex);
226       error += (ctx.string_count - ctx.match_count);
227     }
228
229     GNUNET_REGEX_automaton_destroy (dfa);
230   }
231
232   error += ctx.error;
233
234   return error;
235 }