1 /*
2 Configuration file handling on top of tini
3
4 Copyright (C) Amitay Isaacs 2017
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "replace.h"
21
22 #include <assert.h>
23
24 #include "common/conf.c"
25
26 static void test1(void)
27 {
28 TALLOC_CTX *mem_ctx = talloc_new(NULL);
29 struct conf_context *conf;
30 int ret;
31 bool status;
32
test1_read_handler(uint8_t * buf,size_t buflen,void * private_data)33 ret = conf_init(mem_ctx, &conf);
34 assert(ret == 0);
35 assert(conf != NULL);
36
37 conf_define_section(conf, "section1", NULL);
38 status = conf_valid(conf);
39 assert(status == true);
40
test1_dead_handler(void * private_data)41 conf_define_section(conf, NULL, NULL);
42 status = conf_valid(conf);
43 assert(status == false);
44
45 talloc_free(mem_ctx);
46 }
47
test1(void)48 static void test2(void)
49 {
50 TALLOC_CTX *mem_ctx = talloc_new(NULL);
51 struct conf_context *conf;
52 int ret;
53 bool status;
54
55 ret = conf_init(mem_ctx, &conf);
56 assert(ret == 0);
57 assert(conf != NULL);
58
59 conf_define_string(conf, "section1", "key1", "default", NULL);
60 status = conf_valid(conf);
61 assert(status == false);
62
63 talloc_free(mem_ctx);
64 }
65
66 static void test3(void)
67 {
68 TALLOC_CTX *mem_ctx = talloc_new(NULL);
69 struct conf_context *conf;
70 int ret;
71 bool status;
72
73 ret = conf_init(mem_ctx, &conf);
74 assert(ret == 0);
75 assert(conf != NULL);
76
77 conf_define_section(conf, "section1", NULL);
78 status = conf_valid(conf);
79 assert(status == true);
80
81 conf_define_string(conf, "section1", "key1", NULL, NULL);
82 status = conf_valid(conf);
83 assert(status == true);
84
85 conf_define_string(conf, "section1", "key1", "value1", NULL);
86 status = conf_valid(conf);
87 assert(status == false);
88
89 talloc_free(mem_ctx);
90 }
91
92 static void test4(void)
93 {
94 TALLOC_CTX *mem_ctx = talloc_new(NULL);
95 struct conf_context *conf;
96 int ret;
97 bool status;
98
99 ret = conf_init(mem_ctx, &conf);
100 assert(ret == 0);
101 assert(conf != NULL);
102
103 conf_define_section(conf, "section1", NULL);
104 status = conf_valid(conf);
test2_read_handler(uint8_t * buf,size_t buflen,void * private_data)105 assert(status == true);
106
107 conf_define_string(conf, "section1", "key1", NULL, NULL);
108 status = conf_valid(conf);
109 assert(status == true);
110
111 conf_define_integer(conf, "section1", "key1", 10, NULL);
112 status = conf_valid(conf);
test2_dead_handler(void * private_data)113 assert(status == false);
114
115 talloc_free(mem_ctx);
116 }
117
118 static void test5(void)
119 {
120 TALLOC_CTX *mem_ctx = talloc_new(NULL);
121 struct conf_context *conf;
122 enum conf_type type;
123 int ret;
test2_write_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct comm_context * comm,uint8_t * buf,size_t buflen)124 bool status;
125 const char *s_val;
126 int i_val;
127 bool b_val;
128
129 ret = conf_init(mem_ctx, &conf);
130 assert(ret == 0);
131 assert(conf != NULL);
132
133 conf_define_section(conf, "section1", NULL);
134 status = conf_valid(conf);
135 assert(status == true);
136
137 conf_define_string(conf, "section1", "key1", "value1", NULL);
138 conf_define_integer(conf, "section1", "key2", 10, NULL);
139 conf_define_boolean(conf, "section1", "key3", true, NULL);
140
141 conf_assign_string_pointer(conf, "section1", "key1", &s_val);
142 conf_assign_integer_pointer(conf, "section1", "key2", &i_val);
143 conf_assign_boolean_pointer(conf, "section1", "key3", &b_val);
144
145 status = conf_valid(conf);
146 assert(status == true);
147
148 status = conf_query(conf, "section1", "key1", &type);
149 assert(status == true);
150 assert(type == CONF_STRING);
test2_write_done(struct tevent_req * subreq)151
152 status = conf_query(conf, "section1", "key2", &type);
153 assert(status == true);
154 assert(type == CONF_INTEGER);
155
156 status = conf_query(conf, "section1", "key3", &type);
157 assert(status == true);
158 assert(type == CONF_BOOLEAN);
159
160 assert(strcmp(s_val, "value1") == 0);
161 assert(i_val == 10);
162 assert(b_val == true);
163
164 conf_set_defaults(conf);
165
166 assert(strcmp(s_val, "value1") == 0);
167 assert(i_val == 10);
168 assert(b_val == true);
169
170 talloc_free(mem_ctx);
171 }
172
173 static void test6(void)
test2_timer_handler(struct tevent_context * ev,struct tevent_timer * te,struct timeval cur_time,void * private_data)174 {
175 TALLOC_CTX *mem_ctx = talloc_new(NULL);
176 struct conf_context *conf;
177 int ret;
178 bool status;
179 const char *s_val, *s2_val;
180 int i_val, i2_val;
181 bool b_val, b2_val, is_default;
182
183 ret = conf_init(mem_ctx, &conf);
184 assert(ret == 0);
185 assert(conf != NULL);
186
187 conf_define_section(conf, "section1", NULL);
188 status = conf_valid(conf);
189 assert(status == true);
190
191 conf_define_string(conf, "section1", "key1", "default", NULL);
192 conf_define_integer(conf, "section1", "key2", 10, NULL);
193 conf_define_boolean(conf, "section1", "key3", true, NULL);
194
195 conf_assign_string_pointer(conf, "section1", "key1", &s_val);
196 conf_assign_integer_pointer(conf, "section1", "key2", &i_val);
197 conf_assign_boolean_pointer(conf, "section1", "key3", &b_val);
198
199 status = conf_valid(conf);
200 assert(status == true);
201
202 is_default = false;
203 ret = conf_get_string(conf, "section1", "key1", &s2_val, &is_default);
204 assert(ret == 0);
205 assert(strcmp(s2_val, "default") == 0);
206 assert(is_default == true);
207
208 is_default = false;
209 ret = conf_get_integer(conf, "section1", "key2", &i2_val, &is_default);
210 assert(ret == 0);
211 assert(i2_val == 10);
212 assert(is_default == true);
213
214 is_default = false;
215 ret = conf_get_boolean(conf, "section1", "key3", &b2_val, &is_default);
216 assert(ret == 0);
217 assert(b2_val == true);
218 assert(is_default == true);
219
220 ret = conf_set_string(conf, "section1", "key1", "foobar");
221 assert(ret == 0);
222
223 ret = conf_set_integer(conf, "section1", "key2", 20);
224 assert(ret == 0);
225
226 ret = conf_set_boolean(conf, "section1", "key3", false);
227 assert(ret == 0);
228
229 assert(strcmp(s_val, "foobar") == 0);
230 assert(i_val == 20);
231 assert(b_val == false);
232
233 is_default = true;
234 ret = conf_get_string(conf, "section1", "key1", &s2_val, &is_default);
235 assert(ret == 0);
236 assert(strcmp(s2_val, "foobar") == 0);
237 assert(is_default == false);
238
239 is_default = true;
240 ret = conf_get_integer(conf, "section1", "key2", &i2_val, &is_default);
241 assert(ret == 0);
242 assert(i2_val == 20);
243 assert(is_default == false);
244
245 is_default = true;
246 ret = conf_get_boolean(conf, "section1", "key3", &b2_val, &is_default);
247 assert(ret == 0);
248 assert(b2_val == false);
249 assert(is_default == false);
250
251 conf_dump(conf, stdout);
252
253 conf_set_defaults(conf);
254
255 assert(strcmp(s_val, "default") == 0);
256 assert(i_val == 10);
257 assert(b_val == true);
258
259 talloc_free(mem_ctx);
260 }
261
262 static bool test7_validate_string(const char *key,
263 const char *old_value, const char *new_value,
264 enum conf_update_mode mode)
test3_writer_send(TALLOC_CTX * mem_ctx,struct tevent_context * ev,struct comm_context * comm,size_t * pkt_size,size_t count)265 {
266 return false;
267 }
268
269 static bool test7_validate_integer(const char *key,
270 int old_value, int new_value,
271 enum conf_update_mode mode)
272 {
273 return false;
274 }
275
276 static bool test7_validate_boolean(const char *key,
277 bool old_value, bool new_value,
278 enum conf_update_mode mode)
279 {
280 return false;
281 }
282
283 static void test7(void)
284 {
285 TALLOC_CTX *mem_ctx = talloc_new(NULL);
286 struct conf_context *conf;
287 int ret;
288 bool status;
289 const char *s_val, *s2_val;
290 int i_val, i2_val;
291 bool b_val, b2_val;
292
293 ret = conf_init(mem_ctx, &conf);
294 assert(ret == 0);
295 assert(conf != NULL);
296
297 conf_define_section(conf, "section1", NULL);
298 status = conf_valid(conf);
299 assert(status == true);
300
301 conf_define_string(conf, "section1", "key1", "default",
302 test7_validate_string);
303 conf_define_integer(conf, "section1", "key2", 10,
304 test7_validate_integer);
305 conf_define_boolean(conf, "section1", "key3", true,
306 test7_validate_boolean);
307
308 conf_assign_string_pointer(conf, "section1", "key1", &s_val);
309 conf_assign_integer_pointer(conf, "section1", "key2", &i_val);
310 conf_assign_boolean_pointer(conf, "section1", "key3", &b_val);
311
312 status = conf_valid(conf);
test3_writer_next(struct tevent_req * subreq)313 assert(status == true);
314
315 ret = conf_set_string(conf, "section1", "key1", "default");
316 assert(ret == 0);
317
318 ret = conf_set_string(conf, "section1", "key1", "foobar");
319 assert(ret == EINVAL);
320
321 ret = conf_set_integer(conf, "section1", "key2", 10);
322 assert(ret == 0);
323
324 ret = conf_set_integer(conf, "section1", "key2", 20);
325 assert(ret == EINVAL);
326
327 ret = conf_set_boolean(conf, "section1", "key3", true);
328 assert(ret == 0);
329
330 ret = conf_set_boolean(conf, "section1", "key3", false);
331 assert(ret == EINVAL);
332
333 assert(strcmp(s_val, "default") == 0);
334 assert(i_val == 10);
335 assert(b_val == true);
336
337 ret = conf_get_string(conf, "section1", "key2", &s2_val, NULL);
338 assert(ret == EINVAL);
339
340 ret = conf_get_integer(conf, "section1", "key3", &i2_val, NULL);
341 assert(ret == EINVAL);
342
343 ret = conf_get_boolean(conf, "section1", "key1", &b2_val, NULL);
344 assert(ret == EINVAL);
345
346 talloc_free(mem_ctx);
test3_writer_recv(struct tevent_req * req,int * perr)347 }
348
349 static bool test8_validate(struct conf_context *conf,
350 const char *section,
351 enum conf_update_mode mode)
352 {
353 return false;
354 }
test3_writer(int fd,size_t * pkt_size,size_t count)355
356 static void test8(const char *filename)
357 {
358 TALLOC_CTX *mem_ctx = talloc_new(NULL);
359 struct conf_context *conf;
360 int ret;
361 bool status;
362
363 ret = conf_init(mem_ctx, &conf);
364 assert(ret == 0);
365 assert(conf != NULL);
366
367 conf_define_section(conf, "section1", test8_validate);
368 status = conf_valid(conf);
369 assert(status == true);
370
371 conf_define_string(conf, "section1", "key1", "default", NULL);
372
373 status = conf_valid(conf);
374 assert(status == true);
375
376 ret = conf_load(conf, filename, true);
377 conf_dump(conf, stdout);
378
379 talloc_free(mem_ctx);
380 exit(ret);
381 }
382
383 static void test9(const char *filename, bool ignore_unknown)
384 {
385 TALLOC_CTX *mem_ctx = talloc_new(NULL);
386 struct conf_context *conf;
387 int ret;
388 bool status;
389
390 ret = conf_init(mem_ctx, &conf);
391 assert(ret == 0);
test3_reader_handler(uint8_t * buf,size_t buflen,void * private_data)392 assert(conf != NULL);
393
394 conf_define_section(conf, "section1", NULL);
395
396 conf_define_string(conf, "section1", "key1", "value1", NULL);
397 conf_define_integer(conf, "section1", "key2", 10, NULL);
398 conf_define_boolean(conf, "section1", "key3", true, NULL);
399
400 status = conf_valid(conf);
401 assert(status == true);
402
403 conf_set_boolean(conf, "section1", "key3", false);
404
405 ret = conf_load(conf, filename, ignore_unknown);
406 conf_dump(conf, stdout);
407
test3_reader(int fd,size_t * pkt_size,int count)408 talloc_free(mem_ctx);
409 exit(ret);
410 }
411
412 static void test11(const char *filename)
413 {
414 TALLOC_CTX *mem_ctx = talloc_new(NULL);
415 char reload[PATH_MAX];
416 struct conf_context *conf;
417 int ret;
418 bool status;
419
420 ret = snprintf(reload, sizeof(reload), "%s.reload", filename);
421 assert((size_t)ret < sizeof(reload));
422
423 ret = conf_init(mem_ctx, &conf);
424 assert(ret == 0);
425 assert(conf != NULL);
426
427 conf_define_section(conf, "section1", NULL);
428
429 conf_define_string(conf, "section1", "key1", "value1", NULL);
430 conf_define_integer(conf, "section1", "key2", 10, NULL);
431 conf_define_boolean(conf, "section1", "key3", true, NULL);
432
433 status = conf_valid(conf);
434 assert(status == true);
435
436 ret = conf_load(conf, filename, false);
437 assert(ret == 0);
438
439 ret = rename(reload, filename);
440 assert(ret == 0);
441
442 ret = conf_reload(conf);
test3(void)443 assert(ret == 0);
444
445 conf_dump(conf, stdout);
446
447 talloc_free(mem_ctx);
448 exit(ret);
449 }
450
451 int main(int argc, const char **argv)
452 {
453 int num;
454
455 if (argc < 2) {
456 fprintf(stderr, "Usage: %s <testnum> [<config>]\n", argv[0]);
457 exit(1);
458 }
459
460 num = atoi(argv[1]);
461 if (num > 7 && argc != 3) {
462 fprintf(stderr, "Usage: %s <testnum> [<config>]\n", argv[0]);
463 exit(1);
464 }
465
466 switch (num) {
467 case 1:
468 test1();
469 break;
470
471 case 2:
main(int argc,const char ** argv)472 test2();
473 break;
474
475 case 3:
476 test3();
477 break;
478
479 case 4:
480 test4();
481 break;
482
483 case 5:
484 test5();
485 break;
486
487 case 6:
488 test6();
489 break;
490
491 case 7:
492 test7();
493 break;
494
495 case 8:
496 test8(argv[2]);
497 break;
498
499 case 9:
500 test9(argv[2], true);
501 break;
502
503 case 10:
504 test9(argv[2], false);
505 break;
506
507 case 11:
508 test11(argv[2]);
509 break;
510 }
511
512 return 0;
513 }
514