initial revision
[ucgine.git] / tools / cfzy / cfzy-test / test_expr.c
1 /*
2  * Copyright (c) 2013, Olivier MATZ <zer0@droids-corp.org>
3  * All rights reserved.
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31
32 #include <cfzy_expr.h>
33
34 #include "test_expr.h"
35
36 #define SUCCESS 0
37 #define CANNOT_PARSE -1
38 #define CANNOT_CONVERT_TO_STR -2
39 #define IN_AND_OUT_DIFFERS -3
40 #define CANNOT_EVAL -4
41 #define CANNOT_GET_VARS -5
42
43 /* all variables starting with "A" are evaluated to 1, the other are
44  * evaluated to 0. The variable names "unknown" returns an error
45  * (variable not found). */
46 static int getvalue(const char *varname, void *arg)
47 {
48         (void)arg;
49
50         if (!strcmp(varname, "unknown"))
51                 return -1;
52
53         if (varname[0] == 'A')
54                 return 1;
55         return 0;
56 }
57
58 static int test_one_expr(const char *in)
59 {
60         char out[256];
61         struct cfzy_expr *exp;
62         int ret;
63
64         /* valid expression */
65         exp = cfzy_expr_parse(in);
66         if (exp == NULL)
67                 return CANNOT_PARSE;
68
69         cfzy_expr_graph_dump("test.graph", exp);
70         ret = cfzy_expr_to_str(exp, out, sizeof(out));
71         if (ret < 0) {
72                 cfzy_expr_free(exp);
73                 return CANNOT_CONVERT_TO_STR;
74         }
75
76         if (strncmp(in, out, sizeof(out))) {
77                 cfzy_expr_free(exp);
78                 return IN_AND_OUT_DIFFERS;
79         }
80
81         ret = cfzy_expr_eval(exp, getvalue, NULL);
82         if (ret < 0) {
83                 cfzy_expr_free(exp);
84                 return CANNOT_EVAL;
85         }
86
87         cfzy_expr_free(exp);
88         return ret;
89 }
90
91 static void print_error(const char *in, int err)
92 {
93         printf("Unexpected return value when parsing: <%s>\n", in);
94         switch(err) {
95                 case 0:
96                 case 1:
97                         printf("Test returned %d, but should not\n", err);
98                         break;
99                 case CANNOT_PARSE:
100                         printf("Cannot parse expression\n");
101                         break;
102                 case CANNOT_CONVERT_TO_STR:
103                         printf("Cannot convert expression to string\n");
104                         break;
105                 case IN_AND_OUT_DIFFERS:
106                         printf("Input and output expressions differ\n");
107                         break;
108                 case CANNOT_EVAL:
109                         printf("Cannot evaluate expression\n");
110                         break;
111                 case CANNOT_GET_VARS:
112                         printf("Cannot get variable list\n");
113                         break;
114                 default:
115                         printf("Invalid error %d\n", err);
116                         break;
117         }
118 }
119
120 /* must be called with an expression containing only A and B as vars */
121 static int test_vars(const char *in)
122 {
123         struct cfzy_expr *exp;
124         struct cfzy_list_elt *e;
125         struct cfzy_list_head *list;
126         int ret = 0, count = 0;
127
128         /* valid expression */
129         exp = cfzy_expr_parse(in);
130         if (exp == NULL)
131                 return CANNOT_PARSE;
132
133         list = cfzy_expr_get_vars(exp);
134         if (list == NULL) {
135                 cfzy_expr_free(exp);
136                 return CANNOT_GET_VARS;
137         }
138
139         /* list must contain 2 elements: A and B */
140         TAILQ_FOREACH(e, list, next) {
141                 count++;
142                 if (!strcmp(e->ptr, "A"))
143                         continue;
144                 if (!strcmp(e->ptr, "B"))
145                         continue;
146                 ret = CANNOT_GET_VARS;
147         }
148         if (count != 2)
149                 ret = CANNOT_GET_VARS;
150
151         cfzy_list_free(list, free);
152         cfzy_expr_free(exp);
153         return ret;
154 }
155
156 int test_expr(void)
157 {
158         int ret = 0, err;
159         const char *in;
160
161         in = "true && true";
162         err = test_one_expr(in);
163         if (err != 1) {
164                 print_error(in, err);
165                 ret = -1;
166         }
167
168         in = "(true || false) && false";
169         err = test_one_expr(in);
170         if (err != 0) {
171                 print_error(in, err);
172                 ret = -1;
173         }
174
175         in = "true || (false && false)";
176         err = test_one_expr(in);
177         if (err != 1) {
178                 print_error(in, err);
179                 ret = -1;
180         }
181
182         /* && has priority */
183         in = "true || false && false";
184         err = test_one_expr(in);
185         if (err != 1) {
186                 print_error(in, err);
187                 ret = -1;
188         }
189
190         /* && has priority */
191         in = "false || true && false && true || true && false";
192         err = test_one_expr(in);
193         if (err != 0) {
194                 print_error(in, err);
195                 ret = -1;
196         }
197
198         /* '==' has priority */
199         in = "false == true && false";
200         err = test_one_expr(in);
201         if (err != 0) {
202                 print_error(in, err);
203                 ret = -1;
204         }
205
206         in = "A";
207         err = test_one_expr(in);
208         if (err != 1) {
209                 print_error(in, err);
210                 ret = -1;
211         }
212
213         in = "B";
214         err = test_one_expr(in);
215         if (err != 0) {
216                 print_error(in, err);
217                 ret = -1;
218         }
219
220         in = "true && (true)";
221         err = test_one_expr(in);
222         if (err != 1) {
223                 print_error(in, err);
224                 ret = -1;
225         }
226
227         in = "(!(A1 && !(B1 || A2 && B2 || A_aa)) || "
228                 "(x && !(D && !A) && !(D || E))) == true";
229         err = test_one_expr(in);
230         if (err != 1) {
231                 print_error(in, err);
232                 ret = -1;
233         }
234
235         /* invalid expression */
236         in = "  ";
237         err = test_one_expr(in);
238         if (err != CANNOT_PARSE) {
239                 print_error(in, err);
240                 ret = -1;
241         }
242
243         /* invalid expression */
244         in = "(";
245         err = test_one_expr(in);
246         if (err != CANNOT_PARSE) {
247                 print_error(in, err);
248                 ret = -1;
249         }
250
251         /* invalid expression */
252         in = ")";
253         err = test_one_expr(in);
254         if (err != CANNOT_PARSE) {
255                 print_error(in, err);
256                 ret = -1;
257         }
258
259         /* invalid expression */
260         in = "( )";
261         err = test_one_expr(in);
262         if (err != CANNOT_PARSE) {
263                 print_error(in, err);
264                 ret = -1;
265         }
266
267         /* invalid expression */
268         in = "A &&";
269         err = test_one_expr(in);
270         if (err != CANNOT_PARSE) {
271                 print_error(in, err);
272                 ret = -1;
273         }
274         /* invalid expression */
275         in = "A && && B";
276         err = test_one_expr(in);
277         if (err != CANNOT_PARSE) {
278                 print_error(in, err);
279                 ret = -1;
280         }
281
282         /* invalid expression */
283         in = "A B";
284         err = test_one_expr(in);
285         if (err != CANNOT_PARSE) {
286                 print_error(in, err);
287                 ret = -1;
288         }
289
290         /* invalid expression */
291         in = "A && B || C D";
292         err = test_one_expr(in);
293         if (err != CANNOT_PARSE) {
294                 print_error(in, err);
295                 ret = -1;
296         }
297
298         /* invalid expression */
299         in = "A (B)";
300         err = test_one_expr(in);
301         if (err != CANNOT_PARSE) {
302                 print_error(in, err);
303                 ret = -1;
304         }
305
306         /* invalid expression */
307         in = "&& A B";
308         err = test_one_expr(in);
309         if (err != CANNOT_PARSE) {
310                 print_error(in, err);
311                 ret = -1;
312         }
313
314         /* invalid expression */
315         in = "! A B";
316         err = test_one_expr(in);
317         if (err != CANNOT_PARSE) {
318                 print_error(in, err);
319                 ret = -1;
320         }
321
322         /* invalid expression */
323         in = "A && !|| D";
324         err = test_one_expr(in);
325         if (err != CANNOT_PARSE) {
326                 print_error(in, err);
327                 ret = -1;
328         }
329
330         /* invalid expression */
331         in = "A && !";
332         err = test_one_expr(in);
333         if (err != CANNOT_PARSE) {
334                 print_error(in, err);
335                 ret = -1;
336         }
337
338         /* invalid expression, variable must start with a letter */
339         in = "A && _B";
340         err = test_one_expr(in);
341         if (err != CANNOT_PARSE) {
342                 print_error(in, err);
343                 ret = -1;
344         }
345
346         /* invalid expression, variable must start with a letter and
347          * numbers are not allowed (at least today) */
348         in = "A == 4";
349         err = test_one_expr(in);
350         if (err != CANNOT_PARSE) {
351                 print_error(in, err);
352                 ret = -1;
353         }
354
355         /* valid expression, but unknown variable */
356         in = "unknown";
357         err = test_one_expr(in);
358         if (err != CANNOT_EVAL) {
359                 print_error(in, err);
360                 ret = -1;
361         }
362
363         /* valid expression, but won't display like this because
364          * spaces are stripped */
365         in = " true||(false    && \n false)";
366         err = test_one_expr(in);
367         if (err != IN_AND_OUT_DIFFERS) {
368                 print_error(in, err);
369                 ret = -1;
370         }
371
372         err = test_vars("A && B || true && A == !B");
373         if (err != 0) {
374                 print_error(in, err);
375                 ret = -1;
376         }
377
378         return ret;
379 }