trying to port statvfs call to BSD
[oweals/gnunet.git] / src / util / test_configuration.c
1 /*
2      This file is part of GNUnet.
3      (C) 2003, 2004, 2005, 2006, 2007 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 2, 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 util/test_configuration.c
22  * @brief Test that the configuration module works.
23  * @author Christian Grothoff
24  */
25
26 #include "platform.h"
27 #include "gnunet_common.h"
28 #include "gnunet_configuration_lib.h"
29 #include "gnunet_disk_lib.h"
30
31 #define DEBUG GNUNET_NO
32
33 /* Test Configuration Diffs Options */
34 enum
35 {
36   EDIT_NOTHING,
37   EDIT_SECTION,
38   EDIT_ALL,
39   ADD_NEW_SECTION,
40   ADD_NEW_ENTRY,
41   REMOVE_SECTION,
42   REMOVE_ENTRY,
43   COMPARE
44 #if DEBUG
45     , PRINT
46 #endif
47 };
48
49 static struct GNUNET_CONFIGURATION_Handle *cfg;
50 static struct GNUNET_CONFIGURATION_Handle *cfgDefault;
51
52 struct DiffsCBData
53 {
54   struct GNUNET_CONFIGURATION_Handle *cfg;
55   struct GNUNET_CONFIGURATION_Handle *cfgDiffs;
56   const char *section;
57   int callBackOption;
58   int status;
59 };
60
61
62 static void
63 initDiffsCBData (struct DiffsCBData *cbData)
64 {
65   cbData->section = NULL;
66   cbData->cfg = NULL;
67   cbData->cfgDiffs = NULL;
68   cbData->callBackOption = -1;
69   cbData->status = 0;
70 }
71
72
73 /**
74  * callback function for modifying
75  * and comparing configuration
76 */
77 static void
78 diffsCallBack (void *cls,
79                const char *section, const char *option, const char *value)
80 {
81   struct DiffsCBData *cbData = cls;
82   int cbOption = cbData->callBackOption;
83
84   switch (cbOption)
85     {
86     case EDIT_SECTION:
87       if (NULL == cbData->section)
88         cbData->section = section;
89       if (strcmp (cbData->section, section) == 0)
90         {
91           GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, option,
92                                                  "new-value");
93           GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section,
94                                                  option, "new-value");
95         }
96       break;
97     case EDIT_ALL:
98       GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section, option,
99                                              "new-value");
100       GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section,
101                                              option, "new-value");
102       break;
103     case ADD_NEW_ENTRY:
104       {
105         static int hit = 0;
106         if (hit == 0)
107           {
108             hit = 1;
109             GNUNET_CONFIGURATION_set_value_string (cbData->cfg, section,
110                                                    "new-key", "new-value");
111             GNUNET_CONFIGURATION_set_value_string (cbData->cfgDiffs, section,
112                                                    "new-key", "new-value");
113           }
114         break;
115       }
116     case COMPARE:
117       {
118         int ret;
119         char *diffValue;
120
121         diffValue = NULL;
122         ret =
123           GNUNET_CONFIGURATION_get_value_string (cbData->cfgDiffs, section,
124                                                  option, &diffValue);
125         if (NULL != diffValue)
126           {
127             if (ret == GNUNET_SYSERR || strcmp (diffValue, value) != 0)
128               cbData->status = 1;
129           }
130         else
131           cbData->status = 1;
132         GNUNET_free_non_null (diffValue);
133         break;
134       }
135 #if DEBUG
136     case PRINT:
137       if (NULL == cbData->section)
138         {
139           cbData->section = section;
140           printf ("\nSection: %s\n", section);
141         }
142       else if (strcmp (cbData->section, section) != 0)
143         {
144           cbData->section = section;
145           printf ("\nSection: %s\n", section);
146         }
147       printf ("%s = %s\n", option, value);
148 #endif
149     default:
150       break;
151     }
152 }
153
154
155 static struct GNUNET_CONFIGURATION_Handle *
156 editConfiguration (struct GNUNET_CONFIGURATION_Handle *cfg, int option)
157 {
158   struct DiffsCBData diffsCB;
159   initDiffsCBData (&diffsCB);
160   diffsCB.cfgDiffs = GNUNET_CONFIGURATION_create ();
161
162   switch (option)
163     {
164     case EDIT_SECTION:
165     case EDIT_ALL:
166     case ADD_NEW_ENTRY:
167       diffsCB.callBackOption = option;
168       diffsCB.cfg = cfg;
169       GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &diffsCB);
170       break;
171     case EDIT_NOTHING:
172       /* Do nothing */
173       break;
174     case ADD_NEW_SECTION:
175       {
176         int i;
177         char *key;
178         for (i = 0; i < 5; i++)
179           {
180             GNUNET_asprintf (&key, "key%d", i);
181             GNUNET_CONFIGURATION_set_value_string (cfg, "new-section", key,
182                                                    "new-value");
183             GNUNET_CONFIGURATION_set_value_string (diffsCB.cfgDiffs,
184                                                    "new-section", key,
185                                                    "new-value");
186             GNUNET_free (key);
187           }
188         break;
189       }
190     case REMOVE_SECTION:
191       break;
192     case REMOVE_ENTRY:
193       break;
194     default:
195       break;
196     }
197
198   return diffsCB.cfgDiffs;
199 }
200
201 /**
202  * Checking configuration diffs
203  */
204 static int
205 checkDiffs (struct GNUNET_CONFIGURATION_Handle *cfgDefault, int option)
206 {
207   struct GNUNET_CONFIGURATION_Handle *cfg;
208   struct GNUNET_CONFIGURATION_Handle *cfgDiffs;
209   struct DiffsCBData cbData;
210   int ret;
211   char *diffsFileName;
212
213   initDiffsCBData (&cbData);
214
215   cfg = GNUNET_CONFIGURATION_create ();
216   /* load defaults */
217   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (cfg, NULL));
218
219   /* Modify configuration and save it */
220   cfgDiffs = editConfiguration (cfg, option);
221   diffsFileName =
222     GNUNET_DISK_mktemp ("gnunet-test-configurations-diffs.conf");
223   if (diffsFileName == NULL)
224     {
225       GNUNET_break (0);
226       GNUNET_CONFIGURATION_destroy (cfg);
227       GNUNET_CONFIGURATION_destroy (cfgDiffs);      
228       return 1;
229     }
230   GNUNET_CONFIGURATION_write_diffs (cfgDefault, cfg, diffsFileName);
231   GNUNET_CONFIGURATION_destroy (cfg);
232
233   /* Compare the dumped configuration with modifications done */
234   cfg = GNUNET_CONFIGURATION_create ();
235   GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_parse (cfg, diffsFileName));
236   remove (diffsFileName);
237   cbData.callBackOption = COMPARE;
238   cbData.cfgDiffs = cfgDiffs;
239   GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &cbData);
240   if (1 == (ret = cbData.status))
241     {
242       fprintf (stderr,
243                "Incorrect Configuration Diffs: Diffs may contain data not actually edited\n");
244       goto housekeeping;
245     }
246   cbData.cfgDiffs = cfg;
247   GNUNET_CONFIGURATION_iterate (cfgDiffs, diffsCallBack, &cbData);
248   if ((ret = cbData.status) == 1)
249     fprintf (stderr,
250              "Incorrect Configuration Diffs: Data may be missing in diffs\n");
251
252 housekeeping:
253 #if DEBUG
254   cbData.section = NULL;
255   cbData.callBackOption = PRINT;
256   printf ("\nExpected Diffs:\n");
257   GNUNET_CONFIGURATION_iterate (cfgDiffs, diffsCallBack, &cbData);
258   cbData.section = NULL;
259   printf ("\nActual Diffs:\n");
260   GNUNET_CONFIGURATION_iterate (cfg, diffsCallBack, &cbData);
261 #endif
262   GNUNET_CONFIGURATION_destroy (cfg);
263   GNUNET_CONFIGURATION_destroy (cfgDiffs);
264   GNUNET_free (diffsFileName);
265   return ret;
266 }
267
268
269 static int
270 testConfig ()
271 {
272   char *c;
273   unsigned long long l;
274
275   if (GNUNET_OK !=
276       GNUNET_CONFIGURATION_get_value_string (cfg, "test", "b", &c))
277     return 1;
278   if (0 != strcmp ("b", c))
279     {
280       fprintf (stderr, "Got `%s'\n", c);
281       GNUNET_free (c);
282       return 2;
283     }
284   GNUNET_free (c);
285   if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
286                                                           "test", "five", &l))
287     {
288       GNUNET_break (0);
289       return 3;
290     }
291   if (5 != l)
292     {
293       GNUNET_break (0);
294       return 4;
295     }
296   GNUNET_CONFIGURATION_set_value_string (cfg, "more", "c", "YES");
297   if (GNUNET_NO == GNUNET_CONFIGURATION_get_value_yesno (cfg, "more", "c"))
298     {
299       GNUNET_break (0);
300       return 5;
301     }
302   GNUNET_CONFIGURATION_set_value_number (cfg, "NUMBERS", "TEN", 10);
303   if (GNUNET_OK !=
304       GNUNET_CONFIGURATION_get_value_string (cfg, "NUMBERS", "TEN", &c))
305     {
306       GNUNET_break (0);
307       return 6;
308     }
309   if (0 != strcmp (c, "10"))
310     {
311       GNUNET_free (c);
312       GNUNET_break (0);
313       return 7;
314     }
315   GNUNET_free (c);
316
317   if (GNUNET_OK !=
318       GNUNET_CONFIGURATION_get_value_filename (cfg, "last", "test", &c))
319     {
320       GNUNET_break (0);
321       return 8;
322     }
323 #ifndef MINGW
324   if (0 != strcmp (c, "/hello/world"))
325 #else
326 #define HI "\\hello\\world"
327   if (strstr (c, HI) != c + strlen (c) - strlen (HI))
328 #endif
329     {
330       GNUNET_break (0);
331       GNUNET_free (c);
332       return 9;
333     }
334   GNUNET_free (c);
335
336   return 0;
337 }
338
339 static const char *want[] = {
340   "/Hello",
341   "/File Name",
342   "/World",
343   NULL,
344   NULL,
345 };
346
347 static int
348 check (void *data, const char *fn)
349 {
350   int *idx = data;
351
352   if (0 == strcmp (want[*idx], fn))
353     {
354       (*idx)++;
355       return GNUNET_OK;
356     }
357   GNUNET_break (0);
358   return GNUNET_SYSERR;
359 }
360
361 static int
362 testConfigFilenames ()
363 {
364   int idx;
365
366   idx = 0;
367   if (3 != GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
368                                                          "FILENAMES",
369                                                          "test",
370                                                          &check, &idx))
371     {
372       GNUNET_break (0);
373       return 8;
374     }
375   if (idx != 3)
376     return 16;
377   if (GNUNET_OK !=
378       GNUNET_CONFIGURATION_remove_value_filename (cfg,
379                                                   "FILENAMES",
380                                                   "test", "/File Name"))
381     {
382       GNUNET_break (0);
383       return 24;
384     }
385
386   if (GNUNET_NO !=
387       GNUNET_CONFIGURATION_remove_value_filename (cfg,
388                                                   "FILENAMES",
389                                                   "test", "/File Name"))
390     {
391       GNUNET_break (0);
392       return 32;
393     }
394   if (GNUNET_NO !=
395       GNUNET_CONFIGURATION_remove_value_filename (cfg,
396                                                   "FILENAMES",
397                                                   "test", "Stuff"))
398     {
399       GNUNET_break (0);
400       return 40;
401     }
402
403   if (GNUNET_NO !=
404       GNUNET_CONFIGURATION_append_value_filename (cfg,
405                                                   "FILENAMES",
406                                                   "test", "/Hello"))
407     {
408       GNUNET_break (0);
409       return 48;
410     }
411   if (GNUNET_NO !=
412       GNUNET_CONFIGURATION_append_value_filename (cfg,
413                                                   "FILENAMES",
414                                                   "test", "/World"))
415     {
416       GNUNET_break (0);
417       return 56;
418     }
419
420   if (GNUNET_YES !=
421       GNUNET_CONFIGURATION_append_value_filename (cfg,
422                                                   "FILENAMES",
423                                                   "test", "/File 1"))
424     {
425       GNUNET_break (0);
426       return 64;
427     }
428
429   if (GNUNET_YES !=
430       GNUNET_CONFIGURATION_append_value_filename (cfg,
431                                                   "FILENAMES",
432                                                   "test", "/File 2"))
433     {
434       GNUNET_break (0);
435       return 72;
436     }
437
438   idx = 0;
439   want[1] = "/World";
440   want[2] = "/File 1";
441   want[3] = "/File 2";
442   if (4 != GNUNET_CONFIGURATION_iterate_value_filenames (cfg,
443                                                          "FILENAMES",
444                                                          "test",
445                                                          &check, &idx))
446     {
447       GNUNET_break (0);
448       return 80;
449     }
450   if (idx != 4)
451     {
452       GNUNET_break (0);
453       return 88;
454     }
455   return 0;
456 }
457
458
459 int
460 main (int argc, char *argv[])
461 {
462   int failureCount = 0;
463   char *c;
464
465   GNUNET_log_setup ("test_configuration", "WARNING", NULL);
466   cfg = GNUNET_CONFIGURATION_create ();
467   GNUNET_assert (cfg != NULL);
468   if (GNUNET_OK !=
469       GNUNET_CONFIGURATION_parse (cfg, "test_configuration_data.conf"))
470     {
471       fprintf (stderr, "Failed to parse configuration file\n");
472       GNUNET_CONFIGURATION_destroy (cfg);
473       return 1;
474     }
475   failureCount += testConfig ();
476   failureCount += 2 * testConfigFilenames ();
477
478   if (GNUNET_OK != GNUNET_CONFIGURATION_write (cfg, "/tmp/gnunet-test.conf"))
479     {
480       fprintf (stderr, "Failed to write configuration file\n");
481       GNUNET_CONFIGURATION_destroy (cfg);
482       return 1;
483     }
484   GNUNET_CONFIGURATION_destroy (cfg);
485   GNUNET_assert (0 == UNLINK ("/tmp/gnunet-test.conf"));
486
487   cfg = GNUNET_CONFIGURATION_create ();
488   if (GNUNET_OK !=
489       GNUNET_CONFIGURATION_load (cfg, "test_configuration_data.conf"))
490     {
491       GNUNET_break (0);
492       GNUNET_CONFIGURATION_destroy (cfg);
493       return 1;
494     }
495   if ((GNUNET_OK !=
496        GNUNET_CONFIGURATION_get_value_string (cfg, "TESTING", "WEAKRANDOM",
497                                               &c))
498       || (0 != strcmp (c, "YES")))
499     {
500       GNUNET_break (0);
501       GNUNET_CONFIGURATION_destroy (cfg);
502       return 1;
503     }
504   GNUNET_free (c);
505   GNUNET_CONFIGURATION_destroy (cfg);
506
507   /* Testing configuration diffs */
508   cfgDefault = GNUNET_CONFIGURATION_create ();
509   if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfgDefault, NULL))
510     {
511       GNUNET_break (0);
512       GNUNET_CONFIGURATION_destroy (cfgDefault);
513       return 1;
514     }
515
516   /* Nothing changed in the new configuration */
517   failureCount += checkDiffs (cfgDefault, EDIT_NOTHING);
518
519   /* Modify all entries of the last section */
520   failureCount += checkDiffs (cfgDefault, EDIT_SECTION);
521
522   /* Add a new section */
523   failureCount += checkDiffs (cfgDefault, ADD_NEW_SECTION);
524
525   /* Add a new entry to the last section */
526   failureCount += checkDiffs (cfgDefault, ADD_NEW_ENTRY);
527
528   /* Modify all entries in the configuration */
529   failureCount += checkDiffs (cfgDefault, EDIT_ALL);
530
531   GNUNET_CONFIGURATION_destroy (cfgDefault);
532
533   if (failureCount != 0)
534     {
535       fprintf (stderr, "Test failed: %u\n", failureCount);
536       return 1;
537     }
538   return 0;
539 }