initial revision
[ucgine.git] / tools / cfzy / cfzy-test / test_conftree.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 <stdlib.h>
30 #include <string.h>
31 #include <sys/param.h>
32 #include <libgen.h>
33
34 #include <cfzy_log.h>
35 #include <cfzy_list.h>
36 #include <cfzy_htable.h>
37 #include <cfzy_confnode.h>
38 #include <cfzy_conftree.h>
39 #include <cfzy_dotconfig.h>
40 #include <cfzy_c_hdr.h>
41
42 #include "test_conftree.h"
43
44 #define LOG(level, fmt, args...)                                \
45         CFZY_LOG("test_conftree", level, fmt, ##args)
46
47 #define SUCCESS                      0
48 #define CANNOT_PARSE_CONFTREE       -1
49 #define CANNOT_DUMP_CONFTREE        -2
50 #define CANNOT_FIND_SYMBOL          -3
51 #define CANNOT_EVAL_CONFTREE        -4
52 #define CANNOT_GET_VALUE            -5
53 #define CANNOT_SET_VALUE            -6
54 #define INVALID_VALUE               -7
55 #define CANNOT_FILTER_CONFTREE      -8
56 #define CANNOT_SAVE_CONFTREE_VALUES -9
57
58 /* check that a node is set to the expected value */
59 static int test_one_confnode(const struct cfzy_conftree *conftree,
60                              const char *name, int expected_value)
61 {
62         int val;
63
64         val = cfzy_confnode_get_boolvalue(name, conftree);
65         if (val < 0) {
66                 LOG(DEBUG, "cannot get node value\n");
67                 return CANNOT_GET_VALUE;
68         }
69         if (val != expected_value) {
70                 LOG(DEBUG, "invalid val for %s: val=%d, expect=%d\n",
71                         name, val, expected_value);
72                 return INVALID_VALUE;
73         }
74
75         return SUCCESS;
76 }
77
78 static int test_one_conftree(const char *name)
79 {
80         struct cfzy_list_head *node_list = NULL;
81         struct cfzy_list_elt *e;
82         struct cfzy_conftree *conftree;
83         struct cfzy_confnode *n;
84         int ret;
85
86         conftree = cfzy_conftree_new(name);
87         if (conftree == NULL)
88                 return CANNOT_PARSE_CONFTREE;
89
90         if (cfzy_conftree_evaluate(conftree) < 0) {
91                 LOG(DEBUG, "cannot eval conftree\n");
92                 cfzy_conftree_free(conftree);
93                 return CANNOT_EVAL_CONFTREE;
94         }
95
96         if (cfzy_conftree_dump(conftree, "/tmp/conftree.dump") < 0) {
97                 cfzy_conftree_free(conftree);
98                 return CANNOT_DUMP_CONFTREE;
99         }
100
101         /* node value should be 1 (default) */
102         ret = test_one_confnode(conftree, "MENU1_CONFIG1", 1);
103         if (ret < 0) {
104                 cfzy_conftree_free(conftree);
105                 return ret;
106         }
107
108         /* node value should be 0 (default) */
109         ret = test_one_confnode(conftree, "MENU1_CONFIG2", 0);
110         if (ret < 0) {
111                 cfzy_conftree_free(conftree);
112                 return ret;
113         }
114
115         /* lookup for this node */
116         n = cfzy_htable_lookup(conftree->nodes_htable, "MENU1_CONFIG1");
117         if (n == NULL) {
118                 LOG(DEBUG, "cannot find node\n");
119                 cfzy_conftree_free(conftree);
120                 return CANNOT_FIND_SYMBOL;
121         }
122
123         /* try to assign an invalid value: should fail */
124         if (cfzy_confnode_set_uservalue(n, "dummy") == 0) {
125                 LOG(DEBUG, "set_uservalue returned 0 but should not\n");
126                 cfzy_conftree_free(conftree);
127                 return CANNOT_SET_VALUE;
128         }
129
130         /* set thiis node to NO */
131         if (cfzy_confnode_set_uservalue(n, "n") < 0) {
132                 LOG(DEBUG, "cannot set node value\n");
133                 cfzy_conftree_free(conftree);
134                 return CANNOT_SET_VALUE;
135         }
136
137         /* node value should be 1 because we did not evaluate the tree */
138         ret = test_one_confnode(conftree, "MENU1_CONFIG1", 1);
139         if (ret < 0) {
140                 cfzy_conftree_free(conftree);
141                 return ret;
142         }
143
144         if (cfzy_conftree_evaluate(conftree) < 0) {
145                 LOG(DEBUG, "cannot eval conftree\n");
146                 cfzy_conftree_free(conftree);
147                 return CANNOT_EVAL_CONFTREE;
148         }
149
150         if (cfzy_conftree_dump(conftree, "/tmp/conftree2.dump") < 0) {
151                 cfzy_conftree_free(conftree);
152                 return CANNOT_DUMP_CONFTREE;
153         }
154
155         if (cfzy_conftree_save_values(conftree) < 0) {
156                 cfzy_conftree_free(conftree);
157                 return CANNOT_SAVE_CONFTREE_VALUES;
158         }
159
160         if (cfzy_conftree_dump(conftree, "/tmp/conftree3.dump") < 0) {
161                 cfzy_conftree_free(conftree);
162                 return CANNOT_DUMP_CONFTREE;
163         }
164
165         /* node value should now be 0 */
166         ret = test_one_confnode(conftree, "MENU1_CONFIG1", 0);
167         if (ret < 0) {
168                 cfzy_conftree_free(conftree);
169                 return ret;
170         }
171
172         /* node value should now be 1 (depends on !MENU1_CONFIG1) */
173         ret = test_one_confnode(conftree, "MENU1_CONFIG2", 1);
174         if (ret < 0) {
175                 cfzy_conftree_free(conftree);
176                 return ret;
177         }
178
179         /* test "choice" nodes */
180
181         /* node value should be 0 (default) */
182         ret = test_one_confnode(conftree, "MENU1_CHOICE1", 0);
183         if (ret < 0) {
184                 cfzy_conftree_free(conftree);
185                 return ret;
186         }
187
188         /* node value should be 0 (default) */
189         ret = test_one_confnode(conftree, "MENU1_CHOICE2", 0);
190         if (ret < 0) {
191                 cfzy_conftree_free(conftree);
192                 return ret;
193         }
194
195         /* node value should be 1 (default) */
196         ret = test_one_confnode(conftree, "MENU1_CHOICE3", 1);
197         if (ret < 0) {
198                 cfzy_conftree_free(conftree);
199                 return ret;
200         }
201
202         /* lookup for this node */
203         n = cfzy_htable_lookup(conftree->nodes_htable, "MENU1_CHOICE1");
204         if (n == NULL) {
205                 LOG(DEBUG, "cannot find node\n");
206                 cfzy_conftree_free(conftree);
207                 return CANNOT_FIND_SYMBOL;
208         }
209
210         /* set this node to Y */
211         if (cfzy_confnode_set_uservalue(n, "y") < 0) {
212                 LOG(DEBUG, "cannot set node value\n");
213                 cfzy_conftree_free(conftree);
214                 return CANNOT_SET_VALUE;
215         }
216
217         if (cfzy_conftree_evaluate(conftree) < 0) {
218                 LOG(DEBUG, "cannot eval conftree\n");
219                 cfzy_conftree_free(conftree);
220                 return CANNOT_EVAL_CONFTREE;
221         }
222
223         if (cfzy_conftree_dump(conftree, "/tmp/conftree.dump") < 0) {
224                 cfzy_conftree_free(conftree);
225                 return CANNOT_DUMP_CONFTREE;
226         }
227
228         /* node value should be 1 */
229         ret = test_one_confnode(conftree, "MENU1_CHOICE1", 1);
230         if (ret < 0) {
231                 cfzy_conftree_free(conftree);
232                 return ret;
233         }
234
235         /* node value should be 0 */
236         ret = test_one_confnode(conftree, "MENU1_CHOICE2", 0);
237         if (ret < 0) {
238                 cfzy_conftree_free(conftree);
239                 return ret;
240         }
241
242         /* node value should be 0 */
243         ret = test_one_confnode(conftree, "MENU1_CHOICE3", 0);
244         if (ret < 0) {
245                 cfzy_conftree_free(conftree);
246                 return ret;
247         }
248
249         /* check the "menuconfig" node value, should be 1 (default) */
250         ret = test_one_confnode(conftree, "MENUCONFIG1", 1);
251         if (ret < 0) {
252                 cfzy_conftree_free(conftree);
253                 return ret;
254         }
255
256         /* check which node were changed by the user */
257         node_list = cfzy_conftree_filter(conftree, CFZY_FILTER_F_USR_CHANGED);
258         if (node_list == NULL) {
259                 cfzy_conftree_free(conftree);
260                 return CANNOT_FILTER_CONFTREE;
261         }
262         TAILQ_FOREACH(e, node_list, next) {
263                 n = e->ptr;
264                 printf("node %s\n", cfzy_confnode_name(n));
265         }
266         cfzy_list_free(node_list, NULL);
267
268         /* check which effective value changed */
269         node_list = cfzy_conftree_filter(conftree, CFZY_FILTER_F_EFF_CHANGED);
270         if (node_list == NULL) {
271                 cfzy_conftree_free(conftree);
272                 return CANNOT_FILTER_CONFTREE;
273         }
274         TAILQ_FOREACH(e, node_list, next) {
275                 n = e->ptr;
276                 printf("node2 %s\n", cfzy_confnode_name(n));
277         }
278         cfzy_list_free(node_list, NULL);
279
280         cfzy_conftree_free(conftree);
281         return 0;
282 }
283
284 static int test_one_invalid_conftree(const char *name)
285 {
286         struct cfzy_conftree *conftree;
287
288         conftree = cfzy_conftree_new(name);
289         if (conftree == NULL)
290                 return CANNOT_PARSE_CONFTREE;
291
292         cfzy_conftree_free(conftree);
293         return 0;
294 }
295
296 static void print_error(const char *in, int err)
297 {
298         printf("Unexpected return value when parsing: <%s>\n", in);
299         switch (err) {
300                 case SUCCESS:
301                         printf("Test returned success, but should not\n");
302                         break;
303                 case CANNOT_PARSE_CONFTREE:
304                         printf("Cannot parse configuration tree\n");
305                         break;
306                 case CANNOT_DUMP_CONFTREE:
307                         printf("Cannot dump configuration tree\n");
308                         break;
309                 case CANNOT_EVAL_CONFTREE:
310                         printf("Cannot evalulate configuration tree\n");
311                         break;
312                 case CANNOT_FIND_SYMBOL:
313                         printf("Cannot find symbol\n");
314                         break;
315                 case CANNOT_GET_VALUE:
316                         printf("Cannot get node value\n");
317                         break;
318                 case CANNOT_SET_VALUE:
319                         printf("Cannot set node value\n");
320                         break;
321                 case INVALID_VALUE:
322                         printf("invalid value\n");
323                         break;
324                 case CANNOT_FILTER_CONFTREE:
325                         printf("Cannot filter configuration tree\n");
326                         break;
327                 case CANNOT_SAVE_CONFTREE_VALUES:
328                         printf("Cannot save configuration tree values\n");
329                         break;
330                 default:
331                         printf("Invalid error %d\n", err);
332                         break;
333         }
334 }
335
336 int test_conftree(const char *progname)
337 {
338         char filename[PATH_MAX];
339         char *progdir;
340         int err;
341
342         cfzy_log_set_default_level(CFZY_LOG_DEBUG);
343
344         /* progdir is the directory where confizery-test is located */
345         progdir = strdup(progname);
346         dirname(progdir);
347
348         /* unexistant file */
349         snprintf(filename, sizeof(filename), "foobar");
350         err = test_one_invalid_conftree(filename);
351         if (err != CANNOT_PARSE_CONFTREE) {
352                 print_error(filename, err);
353                 goto fail;
354         }
355
356         /* invalid command */
357         snprintf(filename, sizeof(filename),
358                  "%s/../../src/confizery-test/invalid-configs/"
359                  "invalid-command.cfzy", progdir);
360         err = test_one_invalid_conftree(filename);
361         if (err != CANNOT_PARSE_CONFTREE) {
362                 print_error(filename, err);
363                 goto fail;
364         }
365
366         /* invalid attribute */
367         snprintf(filename, sizeof(filename),
368                  "%s/../../src/confizery-test/invalid-configs/"
369                  "invalid-attribute.cfzy", progdir);
370         err = test_one_invalid_conftree(filename);
371         if (err != CANNOT_PARSE_CONFTREE) {
372                 print_error(filename, err);
373                 goto fail;
374         }
375
376         /* circular dependency */
377         snprintf(filename, sizeof(filename),
378                  "%s/../../src/confizery-test/invalid-configs/"
379                  "circular-dep.cfzy", progdir);
380         err = test_one_invalid_conftree(filename);
381         if (err != CANNOT_PARSE_CONFTREE) {
382                 print_error(filename, err);
383                 goto fail;
384         }
385
386         /* circular dependency */
387         snprintf(filename, sizeof(filename),
388                  "%s/../../src/confizery-test/invalid-configs/"
389                  "circular-dep2.cfzy", progdir);
390         err = test_one_invalid_conftree(filename);
391         if (err != CANNOT_PARSE_CONFTREE) {
392                 print_error(filename, err);
393                 goto fail;
394         }
395
396         /* node not closed */
397         snprintf(filename, sizeof(filename),
398                  "%s/../../src/confizery-test/invalid-configs/"
399                  "node-not-closed.cfzy", progdir);
400         err = test_one_invalid_conftree(filename);
401         if (err != CANNOT_PARSE_CONFTREE) {
402                 print_error(filename, err);
403                 goto fail;
404         }
405
406         /* duplicated config name */
407         snprintf(filename, sizeof(filename),
408                  "%s/../../src/confizery-test/invalid-configs/"
409                  "dup-name.cfzy", progdir);
410         err = test_one_invalid_conftree(filename);
411         if (err != CANNOT_PARSE_CONFTREE) {
412                 print_error(filename, err);
413                 goto fail;
414         }
415
416         /* invalid default value */
417         snprintf(filename, sizeof(filename),
418                  "%s/../../src/confizery-test/invalid-configs/"
419                  "invalid-value.cfzy", progdir);
420         err = test_one_invalid_conftree(filename);
421         if (err != CANNOT_PARSE_CONFTREE) {
422                 print_error(filename, err);
423                 goto fail;
424         }
425
426         /* invalid expression */
427         snprintf(filename, sizeof(filename),
428                  "%s/../../src/confizery-test/invalid-configs/"
429                  "invalid-expr.cfzy", progdir);
430         err = test_one_invalid_conftree(filename);
431         if (err != CANNOT_PARSE_CONFTREE) {
432                 print_error(filename, err);
433                 goto fail;
434         }
435
436         /* valid config */
437
438         /* an example config */
439         snprintf(filename, sizeof(filename),
440                  "%s/../../src/confizery-test/test-configs/"
441                  "conftree.cfzy", progdir);
442         err = test_one_conftree(filename);
443         if (err != SUCCESS) {
444                 print_error(filename, err);
445                 goto fail;
446         }
447
448         free(progdir);
449         return 0;
450
451  fail:
452         free(progdir);
453         return -1;
454 }