chiark / gitweb /
rename recentact to lowvol
[inn-innduct.git] / tests / lib / confparse-t.c
1 /* $Id: confparse-t.c 5955 2002-12-08 09:28:32Z rra $ */
2 /* confparse test suite. */
3
4 #include "config.h"
5 #include "clibrary.h"
6 #include <unistd.h>
7
8 #include "inn/confparse.h"
9 #include "inn/messages.h"
10 #include "inn/vector.h"
11 #include "libinn.h"
12 #include "libtest.h"
13
14 /* Given a FILE *, read from that file, putting the results into a newly
15    allocated buffer, until encountering a line consisting solely of "===".
16    Returns the buffer, NULL on end of file, dies on error. */
17 static char *
18 read_section(FILE *file)
19 {
20     char buf[1024] = "";
21     char *data = NULL;
22     char *status;
23
24     status = fgets(buf, sizeof(buf), file);
25     if (status == NULL)
26         return false;
27     while (1) {
28         if (status == NULL)
29             die("Unexpected end of file while reading tests");
30         if (strcmp(buf, "===\n") == 0)
31             break;
32         if (data == NULL) {
33             data = xstrdup(buf);
34         } else {
35             char *new_data;
36
37             new_data = concat(data, buf, (char *) 0);
38             free(data);
39             data = new_data;
40         }
41         status = fgets(buf, sizeof(buf), file);
42     }
43     return data;
44 }
45
46 /* Read from the given file a configuration file and write it out to
47    config/tmp.  Returns true on success, false on end of file, and dies on
48    any error. */
49 static bool
50 write_test_config(FILE *file)
51 {
52     FILE *tmp;
53     char *config;
54
55     config = read_section(file);
56     if (config == NULL)
57         return false;
58     tmp = fopen("config/tmp", "w");
59     if (tmp == NULL)
60         sysdie("Cannot create config/tmp");
61     if (fputs(config, tmp) == EOF)
62         sysdie("Write error while writing to config/tmp");
63     fclose(tmp);
64     free(config);
65     return true;
66 }
67
68 /* Parse a given config file with errors, setting the appropriate error
69    handler for the duration of the parse to save errors into the errors
70    global.  Returns the resulting config_group. */
71 static struct config_group *
72 parse_error_config(const char *filename)
73 {
74     struct config_group *group;
75
76     errors_capture();
77     group = config_parse_file(filename);
78     errors_uncapture();
79     return group;
80 }
81
82 /* Read in a configuration file from the provided FILE *, write it to disk,
83    parse the temporary config file, and return the resulting config_group in
84    the pointer passed as the second parameter.  Returns true on success,
85    false on end of file. */
86 static bool
87 parse_test_config(FILE *file, struct config_group **group)
88 {
89     if (!write_test_config(file))
90         return false;
91     *group = parse_error_config("config/tmp");
92     unlink("config/tmp");
93     return true;
94 }
95
96 /* Test the error test cases in config/errors, ensuring that they all fail
97    to parse and match the expected error messages.  Takes the current test
98    count and returns the new test count. */
99 static int
100 test_errors(int n)
101 {
102     FILE *errfile;
103     char *expected;
104     struct config_group *group;
105
106     errfile = fopen("config/errors", "r");
107     if (errfile == NULL)
108         sysdie("Cannot open config/errors");
109     while (parse_test_config(errfile, &group)) {
110         expected = read_section(errfile);
111         if (expected == NULL)
112             die("Unexpected end of file while reading error tests");
113         ok(n++, group == NULL);
114         ok_string(n++, expected, errors);
115         free(expected);
116     }
117     fclose(errfile);
118     return n;
119 }
120
121 /* Test the warning test cases in config/warningss, ensuring that they all
122    parse successfully and match the expected error messages.  Takes the
123    current test count and returns the new test count. */
124 static int
125 test_warnings(int n)
126 {
127     FILE *warnfile;
128     char *expected;
129     struct config_group *group;
130
131     warnfile = fopen("config/warnings", "r");
132     if (warnfile == NULL)
133         sysdie("Cannot open config/warnings");
134     while (parse_test_config(warnfile, &group)) {
135         expected = read_section(warnfile);
136         if (expected == NULL)
137             die("Unexpected end of file while reading error tests");
138         ok(n++, group != NULL);
139         ok_string(n++, expected, errors);
140         free(expected);
141     }
142     fclose(warnfile);
143     return n;
144 }
145
146 /* Test the warning test cases in config/warn-bool, ensuring that they all
147    parse successfully and produce the expected error messages when retrieved
148    as bools.  Takes the current test count and returns the new test count. */
149 static int
150 test_warnings_bool(int n)
151 {
152     FILE *warnfile;
153     char *expected;
154     struct config_group *group;
155     bool b_value = false;
156
157     warnfile = fopen("config/warn-bool", "r");
158     if (warnfile == NULL)
159         sysdie("Cannot open config/warn-bool");
160     while (parse_test_config(warnfile, &group)) {
161         expected = read_section(warnfile);
162         if (expected == NULL)
163             die("Unexpected end of file while reading error tests");
164         ok(n++, group != NULL);
165         ok(n++, errors == NULL);
166         errors_capture();
167         ok(n++, !config_param_boolean(group, "parameter", &b_value));
168         ok_string(n++, expected, errors);
169         errors_uncapture();
170         free(expected);
171     }
172     fclose(warnfile);
173     return n;
174 }
175
176 /* Test the warning test cases in config/warn-int, ensuring that they all
177    parse successfully and produce the expected error messages when retrieved
178    as bools.  Takes the current test count and returns the new test count. */
179 static int
180 test_warnings_int(int n)
181 {
182     FILE *warnfile;
183     char *expected;
184     struct config_group *group;
185     long l_value = 1;
186
187     warnfile = fopen("config/warn-int", "r");
188     if (warnfile == NULL)
189         sysdie("Cannot open config/warn-int");
190     while (parse_test_config(warnfile, &group)) {
191         expected = read_section(warnfile);
192         if (expected == NULL)
193             die("Unexpected end of file while reading error tests");
194         ok(n++, group != NULL);
195         ok(n++, errors == NULL);
196         errors_capture();
197         ok(n++, !config_param_integer(group, "parameter", &l_value));
198         ok_string(n++, expected, errors);
199         errors_uncapture();
200         free(expected);
201     }
202     fclose(warnfile);
203     return n;
204 }
205
206 int
207 main(void)
208 {
209     struct config_group *group;
210     bool b_value = false;
211     long l_value = 1;
212     const char *s_value;
213     struct vector *v_value;
214     char *long_param, *long_value;
215     size_t length;
216     int n;
217     FILE *tmpconfig;
218
219     puts("125");
220
221     if (access("config/valid", F_OK) < 0)
222         if (access("lib/config/valid", F_OK) == 0)
223             chdir("lib");
224     group = config_parse_file("config/valid");
225     ok(1, group != NULL);
226     if (group == NULL)
227         exit(1);
228
229     /* Booleans. */
230     ok(2, config_param_boolean(group, "param1", &b_value));
231     ok(3, b_value);
232     b_value = false;
233     ok(4, config_param_boolean(group, "param2", &b_value));
234     ok(5, b_value);
235     b_value = false;
236     ok(6, config_param_boolean(group, "param3", &b_value));
237     ok(7, b_value);
238     ok(8, config_param_boolean(group, "param4", &b_value));
239     ok(9, !b_value);
240     b_value = true;
241     ok(10, config_param_boolean(group, "param5", &b_value));
242     ok(11, !b_value);
243     b_value = true;
244     ok(12, config_param_boolean(group, "param6", &b_value));
245     ok(13, !b_value);
246
247     /* Integers. */
248     ok(14, config_param_integer(group, "int1", &l_value));
249     ok(15, l_value == 0);
250     ok(16, config_param_integer(group, "int2", &l_value));
251     ok(17, l_value == -3);
252     ok(18, !config_param_integer(group, "int3", &l_value));
253     ok(19, l_value == -3);
254     ok(20, config_param_integer(group, "int4", &l_value));
255     ok(21, l_value == 5000);
256     ok(22, config_param_integer(group, "int5", &l_value));
257     ok(23, l_value == 2147483647L);
258     ok(24, config_param_integer(group, "int6", &l_value));
259     ok(25, l_value == (-2147483647L - 1));
260
261     /* Strings. */
262     ok(26, config_param_string(group, "string1", &s_value));
263     ok_string(27, "foo", s_value);
264     ok(28, config_param_string(group, "string2", &s_value));
265     ok_string(29, "bar", s_value);
266     ok(30, config_param_string(group, "string3", &s_value));
267     ok_string(31, "this is a test", s_value);
268     ok(32, config_param_string(group, "string4", &s_value));
269     ok_string(33, "this is a test", s_value);
270     ok(34, config_param_string(group, "string5", &s_value));
271     ok_string(35, "this is \a\b\f\n\r\t\v a test \' of \" escapes \?\\",
272               s_value);
273     ok(36, config_param_string(group, "string6", &s_value));
274     ok_string(37, "# this is not a comment", s_value);
275     ok(38, config_param_string(group, "string7", &s_value));
276     ok_string(39, "lost \nyet?", s_value);
277
278     config_free(group);
279
280     /* Missing newline. */
281     group = config_parse_file("config/no-newline");
282     ok(40, group != NULL);
283     if (group == NULL) {
284         ok(41, false);
285         ok(42, false);
286     } else {
287         ok(41, config_param_string(group, "parameter", &s_value));
288         ok_string(42, "value", s_value);
289         config_free(group);
290     }
291
292     /* Extremely long parameter and value. */
293     tmpconfig = fopen("config/tmp", "w");
294     if (tmpconfig == NULL)
295         sysdie("cannot create config/tmp");
296     long_param = xcalloc(20001, 1);
297     memset(long_param, 'a', 20000);
298     long_value = xcalloc(64 * 1024 + 1, 1);
299     memset(long_value, 'b', 64 * 1024);
300     fprintf(tmpconfig, "%s: \"%s\"; two: %s", long_param, long_value,
301             long_value);
302     fclose(tmpconfig);
303     group = config_parse_file("config/tmp");
304     ok(43, group != NULL);
305     if (group == NULL) {
306         ok(44, false);
307         ok(45, false);
308         ok(46, false);
309         ok(47, false);
310     } else {
311         ok(44, config_param_string(group, long_param, &s_value));
312         ok_string(45, long_value, s_value);
313         ok(46, config_param_string(group, "two", &s_value));
314         ok_string(47, long_value, s_value);
315         config_free(group);
316     }
317     unlink("config/tmp");
318     free(long_param);
319     free(long_value);
320
321     /* Parsing problems exactly on the boundary of a buffer.  This test
322        catches a bug in the parser that caused it to miss the colon at the end
323        of a parameter because the colon was the first character read in a new
324        read of the file buffer. */
325     tmpconfig = fopen("config/tmp", "w");
326     if (tmpconfig == NULL)
327         sysdie("cannot create config/tmp");
328     length = 16 * 1024 - strlen(": baz\nfoo:");
329     long_param = xcalloc(length + 1, 1);
330     memset(long_param, 'c', length);
331     fprintf(tmpconfig, "%s: baz\nfoo: bar\n", long_param);
332     fclose(tmpconfig);
333     group = config_parse_file("config/tmp");
334     ok(48, group != NULL);
335     if (group == NULL) {
336         ok(49, false);
337         ok(50, false);
338         ok(51, false);
339         ok(52, false);
340     } else {
341         ok(49, config_param_string(group, long_param, &s_value));
342         ok_string(50, "baz", s_value);
343         ok(51, config_param_string(group, "foo", &s_value));
344         ok_string(52, "bar", s_value);
345         config_free(group);
346     }
347     unlink("config/tmp");
348     free(long_param);
349
350     /* Alternate line endings. */
351     group = config_parse_file("config/line-endings");
352     ok(53, group != NULL);
353     if (group == NULL)
354         exit(1);
355     ok(54, config_param_boolean(group, "param1", &b_value));
356     ok(55, b_value);
357     b_value = false;
358     ok(56, config_param_boolean(group, "param2", &b_value));
359     ok(57, b_value);
360     b_value = false;
361     ok(58, config_param_boolean(group, "param3", &b_value));
362     ok(59, b_value);
363     ok(60, config_param_boolean(group, "param4", &b_value));
364     ok(61, !b_value);
365     ok(62, config_param_integer(group, "int1", &l_value));
366     ok(63, l_value == 0);
367     ok(64, config_param_integer(group, "int2", &l_value));
368     ok(65, l_value == -3);
369     config_free(group);
370
371     /* Listing parameters. */
372     group = config_parse_file("config/simple");
373     ok(66, group != NULL);
374     if (group == NULL)
375         exit(1);
376     v_value = config_params(group);
377     ok_int(67, 2, v_value->count);
378     ok_int(68, 2, v_value->allocated);
379     if (strcmp(v_value->strings[0], "foo") == 0)
380         ok_string(69, "bar", v_value->strings[1]);
381     else if (strcmp(v_value->strings[0], "bar") == 0)
382         ok_string(69, "foo", v_value->strings[1]);
383     else
384         ok(69, false);
385     vector_free(v_value);
386     config_free(group);
387
388     /* Errors. */
389     group = parse_error_config("config/null");
390     ok(70, group == NULL);
391     ok_string(71, "config/null: invalid NUL character found in file\n",
392               errors);
393     n = test_errors(72);
394     n = test_warnings(n);
395     n = test_warnings_bool(n);
396     n = test_warnings_int(n);
397
398     return 0;
399 }