starter: Add tests for ipsec.conf parser
[strongswan.git] / src / starter / tests / suites / test_parser.c
1 /*
2 * Copyright (C) 2014 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include <unistd.h>
17
18 #include <test_suite.h>
19
20 #include "../../parser/conf_parser.h"
21
22 static char *path = "/tmp/strongswan-starter-parser-test";
23 static conf_parser_t *parser;
24
25 static void create_parser(chunk_t contents)
26 {
27 ck_assert(chunk_write(contents, path, 0022, TRUE));
28 parser = conf_parser_create(path);
29 }
30
31 START_TEARDOWN(teardown_parser)
32 {
33 parser->destroy(parser);
34 unlink(path);
35 }
36 END_TEARDOWN
37
38 START_TEST(test_get_sections_config_setup)
39 {
40 enumerator_t *enumerator;
41
42 create_parser(chunk_from_str(""));
43 ck_assert(parser->parse(parser));
44 enumerator = parser->get_sections(parser, CONF_PARSER_CONFIG_SETUP);
45 ck_assert(enumerator);
46 ck_assert(!enumerator->enumerate(enumerator, NULL));
47 enumerator->destroy(enumerator);
48 parser->destroy(parser);
49
50 create_parser(chunk_from_str("config setup\n\tfoo=bar"));
51 ck_assert(parser->parse(parser));
52 enumerator = parser->get_sections(parser, CONF_PARSER_CONFIG_SETUP);
53 ck_assert(enumerator);
54 ck_assert(!enumerator->enumerate(enumerator, NULL));
55 enumerator->destroy(enumerator);
56 }
57 END_TEST
58
59 START_TEST(test_get_sections_conn)
60 {
61 enumerator_t *enumerator;
62 char *name;
63
64 create_parser(chunk_from_str(""));
65 ck_assert(parser->parse(parser));
66 enumerator = parser->get_sections(parser, CONF_PARSER_CONN);
67 ck_assert(enumerator);
68 ck_assert(!enumerator->enumerate(enumerator, NULL));
69 enumerator->destroy(enumerator);
70 parser->destroy(parser);
71
72 create_parser(chunk_from_str(
73 "conn foo\n"
74 "conn bar\n"
75 "conn foo\n"));
76 ck_assert(parser->parse(parser));
77 enumerator = parser->get_sections(parser, CONF_PARSER_CONN);
78 ck_assert(enumerator);
79 ck_assert(enumerator->enumerate(enumerator, &name));
80 ck_assert_str_eq("foo", name);
81 ck_assert(enumerator->enumerate(enumerator, &name));
82 ck_assert_str_eq("bar", name);
83 ck_assert(!enumerator->enumerate(enumerator, &name));
84 enumerator->destroy(enumerator);
85 }
86 END_TEST
87
88 START_TEST(test_get_section_config_setup)
89 {
90 dictionary_t *dict;
91
92 create_parser(chunk_from_str(""));
93 ck_assert(parser->parse(parser));
94 dict = parser->get_section(parser, CONF_PARSER_CONFIG_SETUP, "foo");
95 ck_assert(dict);
96 dict->destroy(dict);
97 parser->destroy(parser);
98
99 create_parser(chunk_from_str("config setup\n\tfoo=bar"));
100 ck_assert(parser->parse(parser));
101 dict = parser->get_section(parser, CONF_PARSER_CONFIG_SETUP, NULL);
102 ck_assert(dict);
103 dict->destroy(dict);
104 parser->destroy(parser);
105
106 create_parser(chunk_from_str("config setup\n\tfoo=bar"));
107 ck_assert(parser->parse(parser));
108 dict = parser->get_section(parser, CONF_PARSER_CONFIG_SETUP, "foo");
109 ck_assert(dict);
110 dict->destroy(dict);
111 }
112 END_TEST
113
114 START_TEST(test_get_section_conn)
115 {
116 dictionary_t *dict;
117
118 create_parser(chunk_from_str(""));
119 ck_assert(parser->parse(parser));
120 dict = parser->get_section(parser, CONF_PARSER_CONN, "foo");
121 ck_assert(!dict);
122 parser->destroy(parser);
123
124 create_parser(chunk_from_str("conn foo\n"));
125 ck_assert(parser->parse(parser));
126 dict = parser->get_section(parser, CONF_PARSER_CONN, "foo");
127 ck_assert(!parser->get_section(parser, CONF_PARSER_CONN, "bar"));
128 ck_assert(dict);
129 dict->destroy(dict);
130 parser->destroy(parser);
131
132 create_parser(chunk_from_str("conn foo\n\tfoo=bar"));
133 ck_assert(parser->parse(parser));
134 dict = parser->get_section(parser, CONF_PARSER_CONN, "foo");
135 ck_assert(dict);
136 dict->destroy(dict);
137 }
138 END_TEST
139
140 START_TEST(test_enumerate_values)
141 {
142 enumerator_t *enumerator;
143 dictionary_t *dict;
144 char *key, *value;
145 int i;
146
147 create_parser(chunk_from_str(
148 "conn foo\n"
149 " foo=bar\n"
150 " bar=baz"));
151 ck_assert(parser->parse(parser));
152 dict = parser->get_section(parser, CONF_PARSER_CONN, "foo");
153 ck_assert(dict);
154 ck_assert_str_eq("bar", dict->get(dict, "foo"));
155 ck_assert_str_eq("baz", dict->get(dict, "bar"));
156 enumerator = dict->create_enumerator(dict);
157 for (i = 0; enumerator->enumerate(enumerator, &key, &value); i++)
158 {
159 if ((streq(key, "foo") && !streq(value, "bar")) ||
160 (streq(key, "bar") && !streq(value, "baz")))
161 {
162 fail("unexpected setting %s=%s", key, value);
163 }
164 }
165 enumerator->destroy(enumerator);
166 ck_assert_int_eq(i, 2);
167 dict->destroy(dict);
168 }
169 END_TEST
170
171 #define extensibility_config(section) \
172 section "\n" \
173 " foo=bar\n" \
174 " dup=one\n" \
175 " dup=two\n" \
176 "\n" \
177 " nope=val\n" \
178 "\n" \
179 section "\n" \
180 " foo=baz\n" \
181 section "\n" \
182 " answer=42\n" \
183 " nope=\n"
184
185 static struct {
186 char *conf;
187 conf_parser_section_t type;
188 char *name;
189 } extensibility_data[] = {
190 { extensibility_config("config setup"), CONF_PARSER_CONFIG_SETUP, NULL },
191 { extensibility_config("ca ca-foo"), CONF_PARSER_CA, "ca-foo" },
192 { extensibility_config("conn conn-foo"), CONF_PARSER_CONN, "conn-foo" },
193 };
194
195 START_TEST(test_extensibility)
196 {
197 dictionary_t *dict;
198
199 create_parser(chunk_from_str(extensibility_data[_i].conf));
200 ck_assert(parser->parse(parser));
201
202 dict = parser->get_section(parser, extensibility_data[_i].type,
203 extensibility_data[_i].name);
204 ck_assert(dict);
205 ck_assert_str_eq("baz", dict->get(dict, "foo"));
206 ck_assert_str_eq("two", dict->get(dict, "dup"));
207 ck_assert_str_eq("42", dict->get(dict, "answer"));
208 ck_assert(!dict->get(dict, "nope"));
209 ck_assert(!dict->get(dict, "anything"));
210 dict->destroy(dict);
211 }
212 END_TEST
213
214 static struct {
215 char *conf;
216 bool check_section;
217 char *value;
218 } comments_data[] = {
219 { "# conn foo", FALSE, NULL },
220 { "# conn foo\n", FALSE, NULL },
221 { "conn foo # asdf", TRUE, NULL },
222 { "conn foo # asdf", TRUE, NULL },
223 { "conn foo# asdf\n", TRUE, NULL },
224 { "conn foo # asdf\n\tkey=val", TRUE, "val" },
225 { "conn foo # asdf\n#\tkey=val", TRUE, NULL },
226 { "conn foo # asdf\n\t#key=val", TRUE, NULL },
227 { "conn foo # asdf\n\tkey=#val", TRUE, NULL },
228 { "conn foo # asdf\n\tkey=val#asdf", TRUE, "val" },
229 { "conn foo # asdf\n\tkey=\"val#asdf\"", TRUE, "val#asdf" },
230 { "conn foo # asdf\n\tkey=val # asdf\n", TRUE, "val" },
231 { "conn foo # asdf\n# asdf\n\tkey=val\n", TRUE, "val" },
232 { "conn foo # asdf\n\t# asdf\n\tkey=val\n", TRUE, "val" },
233 };
234
235 START_TEST(test_comments)
236 {
237 dictionary_t *dict;
238
239 create_parser(chunk_from_str(comments_data[_i].conf));
240 ck_assert(parser->parse(parser));
241 if (comments_data[_i].check_section)
242 {
243 dict = parser->get_section(parser, CONF_PARSER_CONN, "foo");
244 ck_assert(dict);
245 if (comments_data[_i].value)
246 {
247 ck_assert_str_eq(comments_data[_i].value, dict->get(dict, "key"));
248 }
249 else
250 {
251 ck_assert(!dict->get(dict, "key"));
252 }
253 dict->destroy(dict);
254 }
255 else
256 {
257 ck_assert(!parser->get_section(parser, CONF_PARSER_CONN, "foo"));
258 }
259 }
260 END_TEST
261
262 static struct {
263 char *conf;
264 bool check_section;
265 char *value;
266 } whitespace_data[] = {
267 { "conn foo ", FALSE, NULL },
268 { "conn foo", FALSE, NULL },
269 { "conn foo\n", FALSE, NULL },
270 { "conn foo \n", FALSE, NULL },
271 { "conn foo\n ", FALSE, NULL },
272 { "conn foo\n \n", FALSE, NULL },
273 { "conn foo\nconn bar", TRUE, NULL },
274 { "conn foo\n \nconn bar", TRUE, NULL },
275 { "conn foo\n key=val", FALSE, "val" },
276 { "conn foo\n\tkey=val", FALSE, "val" },
277 { "conn foo\n\t \tkey=val", FALSE, "val" },
278 { "conn foo\n\tkey = val ", FALSE, "val" },
279 };
280
281 START_TEST(test_whitespace)
282 {
283 dictionary_t *dict;
284
285 create_parser(chunk_from_str(whitespace_data[_i].conf));
286 ck_assert(parser->parse(parser));
287 dict = parser->get_section(parser, CONF_PARSER_CONN, "foo");
288 ck_assert(dict);
289 if (whitespace_data[_i].value)
290 {
291 ck_assert_str_eq(whitespace_data[_i].value, dict->get(dict, "key"));
292 }
293 else
294 {
295 ck_assert(!dict->get(dict, "key"));
296 }
297 dict->destroy(dict);
298 if (whitespace_data[_i].check_section)
299 {
300 dict = parser->get_section(parser, CONF_PARSER_CONN, "bar");
301 ck_assert(dict);
302 dict->destroy(dict);
303 }
304 else
305 {
306 ck_assert(!parser->get_section(parser, CONF_PARSER_CONN, "bar"));
307 }
308 }
309 END_TEST
310
311 static struct {
312 bool valid;
313 char *conf;
314 char *section;
315 char *value;
316 } strings_data[] = {
317 { FALSE, "\"conn foo\"", NULL, NULL },
318 { TRUE, "conn \"foo\"", "foo", NULL },
319 { FALSE, "conn foo bar", NULL, NULL },
320 { TRUE, "conn \"foo bar\"", "foo bar", NULL },
321 { TRUE, "conn \"#foo\"", "#foo", NULL },
322 { FALSE, "conn foo\n\t\"key=val\"", "foo", NULL },
323 { TRUE, "conn foo\n\t\"key\"=val", "foo", "val" },
324 { TRUE, "conn foo\n\tkey=val ue", "foo", "val ue" },
325 { TRUE, "conn foo\n\tkey=val ue", "foo", "val ue" },
326 { TRUE, "conn foo\n\tkey=\"val ue\"", "foo", "val ue" },
327 { TRUE, "conn foo\n\tkey=\"val\\nue\"", "foo", "val\nue" },
328 };
329
330 START_TEST(test_strings)
331 {
332 dictionary_t *dict;
333
334 create_parser(chunk_from_str(strings_data[_i].conf));
335 ck_assert(parser->parse(parser) == strings_data[_i].valid);
336 if (strings_data[_i].section)
337 {
338 dict = parser->get_section(parser, CONF_PARSER_CONN,
339 strings_data[_i].section);
340 ck_assert(dict);
341 if (strings_data[_i].value)
342 {
343 ck_assert_str_eq(strings_data[_i].value, dict->get(dict, "key"));
344 }
345 else
346 {
347 ck_assert(!dict->get(dict, "key"));
348 }
349 dict->destroy(dict);
350 }
351 }
352 END_TEST
353
354 START_TEST(test_refcounting)
355 {
356 dictionary_t *dict;
357
358 create_parser(chunk_from_str(
359 "conn foo\n"
360 " key=val"));
361
362 ck_assert(parser->parse(parser));
363 dict = parser->get_section(parser, CONF_PARSER_CONN, "foo");
364 ck_assert(dict);
365 ck_assert_str_eq("val", dict->get(dict, "key"));
366 parser->destroy(parser);
367 ck_assert_str_eq("val", dict->get(dict, "key"));
368 dict->destroy(dict);
369 }
370 END_TEST
371
372 START_TEST(test_also)
373 {
374 dictionary_t *dict;
375
376 create_parser(chunk_from_str(
377 "conn A\n"
378 " key=vala\n"
379 " keya=val1\n"
380 " unset=set\n"
381 "conn B\n"
382 " also=A\n"
383 " key=valb\n"
384 " keyb=val2\n"
385 " unset=\n"
386 "conn C\n"
387 " keyc=val3\n"
388 " unset=set again\n"
389 " also=B\n"
390 "conn D\n"
391 " keyd=val4\n"
392 " also=A\n"
393 " also=B\n"
394 "conn E\n"
395 " keye=val5\n"
396 " also=B\n"
397 " also=A\n"
398 ""));
399
400 ck_assert(parser->parse(parser));
401 dict = parser->get_section(parser, CONF_PARSER_CONN, "B");
402 ck_assert(dict);
403 ck_assert_str_eq("valb", dict->get(dict, "key"));
404 ck_assert_str_eq("val1", dict->get(dict, "keya"));
405 ck_assert_str_eq("val2", dict->get(dict, "keyb"));
406 ck_assert(!dict->get(dict, "unset"));
407 dict->destroy(dict);
408 dict = parser->get_section(parser, CONF_PARSER_CONN, "C");
409 ck_assert(dict);
410 ck_assert_str_eq("valb", dict->get(dict, "key"));
411 ck_assert_str_eq("val1", dict->get(dict, "keya"));
412 ck_assert_str_eq("val2", dict->get(dict, "keyb"));
413 ck_assert_str_eq("val3", dict->get(dict, "keyc"));
414 ck_assert_str_eq("set again", dict->get(dict, "unset"));
415 dict->destroy(dict);
416 /* since B includes A too the inclusion in D and E has no effect */
417 dict = parser->get_section(parser, CONF_PARSER_CONN, "D");
418 ck_assert(dict);
419 ck_assert_str_eq("valb", dict->get(dict, "key"));
420 ck_assert_str_eq("val1", dict->get(dict, "keya"));
421 ck_assert_str_eq("val2", dict->get(dict, "keyb"));
422 ck_assert(!dict->get(dict, "keyc"));
423 ck_assert_str_eq("val4", dict->get(dict, "keyd"));
424 ck_assert(!dict->get(dict, "unset"));
425 dict->destroy(dict);
426 dict = parser->get_section(parser, CONF_PARSER_CONN, "E");
427 ck_assert(dict);
428 ck_assert_str_eq("valb", dict->get(dict, "key"));
429 ck_assert_str_eq("val1", dict->get(dict, "keya"));
430 ck_assert_str_eq("val2", dict->get(dict, "keyb"));
431 ck_assert(!dict->get(dict, "keyc"));
432 ck_assert(!dict->get(dict, "keyd"));
433 ck_assert_str_eq("val5", dict->get(dict, "keye"));
434 ck_assert(!dict->get(dict, "unset"));
435 dict->destroy(dict);
436 }
437 END_TEST
438
439 START_TEST(test_ambiguous)
440 {
441 dictionary_t *dict;
442
443 create_parser(chunk_from_str(
444 "conn A\n"
445 " key=vala\n"
446 "conn B\n"
447 " key=valb\n"
448 "conn C\n"
449 " also=A\n"
450 " also=B\n"
451 "conn D\n"
452 " also=B\n"
453 " also=A\n"
454 "conn E\n"
455 " also=C\n"
456 " also=D\n"
457 "conn F\n"
458 " also=D\n"
459 " also=C\n"));
460
461 ck_assert(parser->parse(parser));
462 dict = parser->get_section(parser, CONF_PARSER_CONN, "E");
463 ck_assert(dict);
464 ck_assert_str_eq("valb", dict->get(dict, "key"));
465 dict->destroy(dict);
466 dict = parser->get_section(parser, CONF_PARSER_CONN, "F");
467 ck_assert(dict);
468 ck_assert_str_eq("vala", dict->get(dict, "key"));
469 dict->destroy(dict);
470 }
471 END_TEST
472
473 Suite *parser_suite_create()
474 {
475 Suite *s;
476 TCase *tc;
477
478 s = suite_create("ipsec.conf parser");
479
480 tc = tcase_create("get_section(s)");
481 tcase_add_checked_fixture(tc, NULL, teardown_parser);
482 tcase_add_test(tc, test_get_sections_config_setup);
483 tcase_add_test(tc, test_get_sections_conn);
484 tcase_add_test(tc, test_get_section_config_setup);
485 tcase_add_test(tc, test_get_section_conn);
486 suite_add_tcase(s, tc);
487
488 tc = tcase_create("enumerate settings");
489 tcase_add_checked_fixture(tc, NULL, teardown_parser);
490 tcase_add_test(tc, test_enumerate_values);
491 suite_add_tcase(s, tc);
492
493 tc = tcase_create("extensibility");
494 tcase_add_checked_fixture(tc, NULL, teardown_parser);
495 tcase_add_loop_test(tc, test_extensibility, 0, countof(extensibility_data));
496 suite_add_tcase(s, tc);
497
498 tc = tcase_create("comments");
499 tcase_add_checked_fixture(tc, NULL, teardown_parser);
500 tcase_add_loop_test(tc, test_comments, 0, countof(comments_data));
501 suite_add_tcase(s, tc);
502
503 tc = tcase_create("whitespace");
504 tcase_add_checked_fixture(tc, NULL, teardown_parser);
505 tcase_add_loop_test(tc, test_whitespace, 0, countof(whitespace_data));
506 suite_add_tcase(s, tc);
507
508 tc = tcase_create("strings");
509 tcase_add_checked_fixture(tc, NULL, teardown_parser);
510 tcase_add_loop_test(tc, test_strings, 0, countof(strings_data));
511 suite_add_tcase(s, tc);
512
513 tc = tcase_create("refcounting");
514 tcase_add_test(tc, test_refcounting);
515 suite_add_tcase(s, tc);
516
517 tc = tcase_create("also=");
518 tcase_add_checked_fixture(tc, NULL, teardown_parser);
519 tcase_add_test(tc, test_also);
520 tcase_add_test(tc, test_ambiguous);
521 suite_add_tcase(s, tc);
522
523 return s;
524 }