1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
7 * Tests for confmgt.c module that we use to parse various
8 * configuration/state file types.
11 #define CONFMGT_PRIVATE
14 #include "core/or/or.h"
15 #include "lib/encoding/confline.h"
16 #include "feature/nodelist/routerset.h"
17 #include "lib/confmgt/confmgt.h"
18 #include "test/test.h"
19 #include "test/log_test_helpers.h"
21 #include "lib/confmgt/unitparse.h"
23 typedef struct test_struct_t
{
41 config_line_t
*mixed_lines
;
42 routerset_t
*routerset
;
44 config_line_t
*mixed_hidden_lines
;
46 config_line_t
*extra_lines
;
49 static test_struct_t test_struct_t_dummy
;
51 #define VAR(varname,conftype,member,initvalue) \
52 CONFIG_VAR_ETYPE(test_struct_t, varname, conftype, member, 0, initvalue)
53 #define V(member,conftype,initvalue) \
54 VAR(#member, conftype, member, initvalue)
55 #define OBSOLETE(varname) \
56 CONFIG_VAR_OBSOLETE(varname)
58 static const config_var_t test_vars
[] = {
59 V(s
, STRING
, "hello"),
60 V(fn
, FILENAME
, NULL
),
63 V(deprecated_int
, INT
, "3"),
65 V(interval
, INTERVAL
, "10 seconds"),
66 V(msec_interval
, MSEC_INTERVAL
, "150 msec"),
67 V(mem
, MEMUNIT
, "10 MB"),
69 V(boolean
, BOOL
, "0"),
70 V(autobool
, AUTOBOOL
, "auto"),
71 V(time
, ISOTIME
, NULL
),
73 V(csv_interval
, CSV_INTERVAL
, "5 seconds"),
74 V(lines
, LINELIST
, NULL
),
75 VAR("MixedLines", LINELIST_V
, mixed_lines
, NULL
),
76 VAR("LineTypeA", LINELIST_S
, mixed_lines
, NULL
),
77 VAR("LineTypeB", LINELIST_S
, mixed_lines
, NULL
),
80 .member
= { .name
= "routerset",
81 .type
= CONFIG_TYPE_EXTENDED
,
82 .type_def
= &ROUTERSET_type_defn
,
83 .offset
= offsetof(test_struct_t
, routerset
),
86 VAR("__HiddenInt", POSINT
, hidden_int
, "0"),
87 VAR("MixedHiddenLines", LINELIST_V
, mixed_hidden_lines
, NULL
),
88 VAR("__HiddenLineA", LINELIST_S
, mixed_hidden_lines
, NULL
),
89 VAR("VisibleLineB", LINELIST_S
, mixed_hidden_lines
, NULL
),
94 static config_abbrev_t test_abbrevs
[] = {
95 { "uint", "pos", 0, 0 },
96 { "float", "dbl", 0, 1 },
100 static config_deprecation_t test_deprecation_notes
[] = {
101 { "deprecated_int", "This integer is deprecated." },
106 test_validate_cb(const void *old_options
, void *options
, char **msg
)
110 test_struct_t
*ts
= options
;
112 if (ts
->i
== 0xbad) {
113 *msg
= tor_strdup("bad value for i");
119 #define TEST_MAGIC 0x1337
121 static const config_format_t test_fmt
= {
122 .size
= sizeof(test_struct_t
),
126 offsetof(test_struct_t
, magic
),
128 .abbrevs
= test_abbrevs
,
129 .deprecations
= test_deprecation_notes
,
131 .legacy_validate_fn
= test_validate_cb
,
134 /* Make sure that config_init sets everything to the right defaults. */
136 test_confparse_init(void *arg
)
139 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
140 config_mgr_freeze(mgr
);
141 test_struct_t
*tst
= config_new(mgr
);
142 config_init(mgr
, tst
);
144 // Make sure that options are initialized right. */
145 tt_str_op(tst
->s
, OP_EQ
, "hello");
146 tt_ptr_op(tst
->fn
, OP_EQ
, NULL
);
147 tt_int_op(tst
->pos
, OP_EQ
, 0);
148 tt_int_op(tst
->i
, OP_EQ
, -10);
149 tt_int_op(tst
->deprecated_int
, OP_EQ
, 3);
150 tt_u64_op(tst
->u64
, OP_EQ
, 0);
151 tt_int_op(tst
->interval
, OP_EQ
, 10);
152 tt_int_op(tst
->msec_interval
, OP_EQ
, 150);
153 tt_u64_op(tst
->mem
, OP_EQ
, 10 * 1024 * 1024);
154 tt_double_op(tst
->dbl
, OP_LT
, .0000000001);
155 tt_double_op(tst
->dbl
, OP_GT
, -0.0000000001);
156 tt_int_op(tst
->boolean
, OP_EQ
, 0);
157 tt_int_op(tst
->autobool
, OP_EQ
, -1);
158 tt_i64_op(tst
->time
, OP_EQ
, 0);
159 tt_ptr_op(tst
->csv
, OP_EQ
, NULL
);
160 tt_int_op(tst
->csv_interval
, OP_EQ
, 5);
161 tt_ptr_op(tst
->lines
, OP_EQ
, NULL
);
162 tt_ptr_op(tst
->mixed_lines
, OP_EQ
, NULL
);
163 tt_int_op(tst
->hidden_int
, OP_EQ
, 0);
166 config_free(mgr
, tst
);
167 config_mgr_free(mgr
);
170 static const char simple_settings
[] =
172 "fn /simple/test of the\n"
173 "uint 77\n" // this is an abbrev
175 "u64 1000000000000 \n"
176 "interval 5 minutes \n"
177 "msec_interval 5 minutes \n"
182 "time 2019-06-14 13:58:51\n"
183 "csv configuration, parsing , system \n"
184 "csv_interval 10 seconds, 5 seconds, 10 hours\n"
189 "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
191 "__hiddenlineA XYZ\n"
192 "visiblelineB ABC\n";
194 /* Return a configuration object set up from simple_settings above. */
195 static test_struct_t
*
196 get_simple_config(const config_mgr_t
*mgr
)
198 test_struct_t
*result
= NULL
;
199 test_struct_t
*tst
= config_new(mgr
);
200 config_line_t
*lines
= NULL
;
203 config_init(mgr
, tst
);
205 int r
= config_get_lines(simple_settings
, &lines
, 0);
206 tt_int_op(r
, OP_EQ
, 0);
207 r
= config_assign(mgr
, tst
, lines
, 0, &msg
);
208 tt_int_op(r
, OP_EQ
, 0);
209 tt_ptr_op(msg
, OP_EQ
, NULL
);
212 tst
= NULL
; // prevent free
215 config_free_lines(lines
);
216 config_free(mgr
, tst
);
220 /* Make sure that config_assign can parse things. */
222 test_confparse_assign_simple(void *arg
)
225 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
226 config_mgr_freeze(mgr
);
227 test_struct_t
*tst
= get_simple_config(mgr
);
229 tt_str_op(tst
->s
, OP_EQ
, "this is a");
230 tt_str_op(tst
->fn
, OP_EQ
, "/simple/test of the");
231 tt_int_op(tst
->pos
, OP_EQ
, 77);
232 tt_int_op(tst
->i
, OP_EQ
, 3);
233 tt_int_op(tst
->deprecated_int
, OP_EQ
, 3);
234 tt_u64_op(tst
->u64
, OP_EQ
, UINT64_C(1000000000000));
235 tt_int_op(tst
->interval
, OP_EQ
, 5 * 60);
236 tt_int_op(tst
->msec_interval
, OP_EQ
, 5 * 60 * 1000);
237 tt_u64_op(tst
->mem
, OP_EQ
, 10);
238 tt_double_op(tst
->dbl
, OP_LT
, 6.060843);
239 tt_double_op(tst
->dbl
, OP_GT
, 6.060841);
240 tt_int_op(tst
->boolean
, OP_EQ
, 1);
241 tt_int_op(tst
->autobool
, OP_EQ
, 0);
242 tt_i64_op(tst
->time
, OP_EQ
, 1560520731);
243 tt_ptr_op(tst
->csv
, OP_NE
, NULL
);
244 tt_int_op(smartlist_len(tst
->csv
), OP_EQ
, 3);
245 tt_str_op(smartlist_get(tst
->csv
, 0), OP_EQ
, "configuration");
246 tt_str_op(smartlist_get(tst
->csv
, 1), OP_EQ
, "parsing");
247 tt_str_op(smartlist_get(tst
->csv
, 2), OP_EQ
, "system");
248 tt_int_op(tst
->csv_interval
, OP_EQ
, 10);
249 tt_int_op(tst
->hidden_int
, OP_EQ
, 11);
251 tt_assert(tst
->lines
);
252 tt_str_op(tst
->lines
->key
, OP_EQ
, "lines");
253 tt_str_op(tst
->lines
->value
, OP_EQ
, "hello");
254 tt_assert(tst
->lines
->next
);
255 tt_str_op(tst
->lines
->next
->key
, OP_EQ
, "lines");
256 tt_str_op(tst
->lines
->next
->value
, OP_EQ
, "world");
257 tt_assert(!tst
->lines
->next
->next
);
259 tt_assert(tst
->mixed_lines
);
260 tt_str_op(tst
->mixed_lines
->key
, OP_EQ
, "LineTypeA");
261 tt_str_op(tst
->mixed_lines
->value
, OP_EQ
, "i d");
262 tt_assert(tst
->mixed_lines
->next
);
263 tt_str_op(tst
->mixed_lines
->next
->key
, OP_EQ
, "LineTypeB");
264 tt_str_op(tst
->mixed_lines
->next
->value
, OP_EQ
, "i c");
265 tt_assert(!tst
->mixed_lines
->next
->next
);
267 tt_assert(tst
->mixed_hidden_lines
);
268 tt_str_op(tst
->mixed_hidden_lines
->key
, OP_EQ
, "__HiddenLineA");
269 tt_str_op(tst
->mixed_hidden_lines
->value
, OP_EQ
, "XYZ");
270 tt_assert(tst
->mixed_hidden_lines
->next
);
271 tt_str_op(tst
->mixed_hidden_lines
->next
->key
, OP_EQ
, "VisibleLineB");
272 tt_str_op(tst
->mixed_hidden_lines
->next
->value
, OP_EQ
, "ABC");
273 tt_assert(!tst
->mixed_hidden_lines
->next
->next
);
275 tt_assert(config_check_ok(mgr
, tst
, LOG_ERR
));
278 config_free(mgr
, tst
);
279 config_mgr_free(mgr
);
282 /* Try to assign to an obsolete option, and make sure we get a warning. */
284 test_confparse_assign_obsolete(void *arg
)
287 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
288 config_mgr_freeze(mgr
);
289 test_struct_t
*tst
= get_simple_config(mgr
);
290 config_line_t
*lines
= NULL
;
293 config_init(mgr
, tst
);
295 int r
= config_get_lines("obsolete option here",
297 tt_int_op(r
, OP_EQ
, 0);
298 setup_capture_of_logs(LOG_WARN
);
299 r
= config_assign(mgr
, tst
, lines
, 0, &msg
);
300 tt_int_op(r
, OP_EQ
, 0);
301 tt_ptr_op(msg
, OP_EQ
, NULL
);
302 expect_single_log_msg_containing("Skipping obsolete configuration option");
305 teardown_capture_of_logs();
306 config_free(mgr
, tst
);
307 config_free_lines(lines
);
309 config_mgr_free(mgr
);
312 /* Try to assign to an deprecated option, and make sure we get a warning
313 * but the assignment works anyway. */
315 test_confparse_assign_deprecated(void *arg
)
318 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
319 config_mgr_freeze(mgr
);
320 test_struct_t
*tst
= get_simple_config(mgr
);
321 config_line_t
*lines
= NULL
;
324 config_init(mgr
, tst
);
326 int r
= config_get_lines("deprecated_int 7",
328 tt_int_op(r
, OP_EQ
, 0);
329 setup_capture_of_logs(LOG_WARN
);
330 r
= config_assign(mgr
, tst
, lines
, CAL_WARN_DEPRECATIONS
, &msg
);
331 tt_int_op(r
, OP_EQ
, 0);
332 tt_ptr_op(msg
, OP_EQ
, NULL
);
333 expect_single_log_msg_containing("This integer is deprecated.");
335 tt_int_op(tst
->deprecated_int
, OP_EQ
, 7);
337 tt_assert(config_check_ok(mgr
, tst
, LOG_ERR
));
340 teardown_capture_of_logs();
341 config_free(mgr
, tst
);
342 config_free_lines(lines
);
344 config_mgr_free(mgr
);
347 /* Try to re-assign an option name that has been deprecated in favor of
350 test_confparse_assign_replaced(void *arg
)
353 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
354 config_mgr_freeze(mgr
);
355 test_struct_t
*tst
= get_simple_config(mgr
);
356 config_line_t
*lines
= NULL
;
359 config_init(mgr
, tst
);
361 int r
= config_get_lines("float 1000\n", &lines
, 0);
362 tt_int_op(r
, OP_EQ
, 0);
363 setup_capture_of_logs(LOG_WARN
);
364 r
= config_assign(mgr
, tst
, lines
, CAL_WARN_DEPRECATIONS
, &msg
);
365 tt_int_op(r
, OP_EQ
, 0);
366 tt_ptr_op(msg
, OP_EQ
, NULL
);
367 expect_single_log_msg_containing("use 'dbl' instead.");
369 tt_double_op(tst
->dbl
, OP_GT
, 999.999);
370 tt_double_op(tst
->dbl
, OP_LT
, 1000.001);
373 teardown_capture_of_logs();
374 config_free(mgr
, tst
);
375 config_free_lines(lines
);
377 config_mgr_free(mgr
);
380 /* Try to set a linelist value with no option. */
382 test_confparse_assign_emptystring(void *arg
)
385 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
386 config_mgr_freeze(mgr
);
387 test_struct_t
*tst
= get_simple_config(mgr
);
388 config_line_t
*lines
= NULL
;
391 config_init(mgr
, tst
);
393 int r
= config_get_lines("lines\n", &lines
, 0);
394 tt_int_op(r
, OP_EQ
, 0);
395 setup_capture_of_logs(LOG_WARN
);
396 r
= config_assign(mgr
, tst
, lines
, 0, &msg
);
397 tt_int_op(r
, OP_EQ
, 0);
398 tt_ptr_op(msg
, OP_EQ
, NULL
);
399 expect_single_log_msg_containing("has no value");
402 teardown_capture_of_logs();
403 config_free(mgr
, tst
);
404 config_free_lines(lines
);
406 config_mgr_free(mgr
);
409 /* Try to set a the same option twice; make sure we get a warning. */
411 test_confparse_assign_twice(void *arg
)
414 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
415 config_mgr_freeze(mgr
);
416 test_struct_t
*tst
= get_simple_config(mgr
);
417 config_line_t
*lines
= NULL
;
420 config_init(mgr
, tst
);
422 int r
= config_get_lines("pos 10\n"
423 "pos 99\n", &lines
, 0);
424 tt_int_op(r
, OP_EQ
, 0);
425 setup_capture_of_logs(LOG_WARN
);
426 r
= config_assign(mgr
, tst
, lines
, 0, &msg
);
427 tt_int_op(r
, OP_EQ
, 0);
428 tt_ptr_op(msg
, OP_EQ
, NULL
);
429 expect_single_log_msg_containing("used more than once");
432 teardown_capture_of_logs();
433 config_free(mgr
, tst
);
434 config_free_lines(lines
);
436 config_mgr_free(mgr
);
439 typedef struct badval_test_t
{
441 const char *expect_msg
;
444 /* Try to set an option and make sure that we get a failure and an expected
447 test_confparse_assign_badval(void *arg
)
449 const badval_test_t
*bt
= arg
;
450 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
451 config_mgr_freeze(mgr
);
452 test_struct_t
*tst
= get_simple_config(mgr
);
453 config_line_t
*lines
= NULL
;
456 config_init(mgr
, tst
);
458 int r
= config_get_lines(bt
->cfg
, &lines
, 0);
459 tt_int_op(r
, OP_EQ
, 0);
460 setup_capture_of_logs(LOG_WARN
);
461 r
= config_assign(mgr
, tst
, lines
, 0, &msg
);
462 tt_int_op(r
, OP_LT
, 0);
463 tt_ptr_op(msg
, OP_NE
, NULL
);
464 if (! strstr(msg
, bt
->expect_msg
)) {
465 TT_DIE(("'%s' did not contain '%s'" , msg
, bt
->expect_msg
));
469 teardown_capture_of_logs();
470 config_free(mgr
, tst
);
471 config_free_lines(lines
);
473 config_mgr_free(mgr
);
476 /* Various arguments for badval test.
478 * Note that the expected warnings here are _very_ truncated, since we
479 * are writing these tests before a refactoring that we expect will
482 static const badval_test_t bv_notint
= { "pos X\n", "malformed" };
483 static const badval_test_t bv_negint
= { "pos -10\n", "out of bounds" };
484 static const badval_test_t bv_badu64
= { "u64 u64\n", "malformed" };
485 static const badval_test_t bv_dbl1
= { "dbl xxx\n", "Could not convert" };
486 static const badval_test_t bv_dbl2
= { "dbl 1.0 xx\n", "Could not convert" };
487 static const badval_test_t bv_dbl3
= {
488 "dbl 1e-10000\n", "too small to express" };
489 static const badval_test_t bv_dbl4
= {
490 "dbl 1e1000\n", "too large to express" };
491 static const badval_test_t bv_dbl5
= {
492 "dbl -1e-10000\n", "too small to express" };
493 static const badval_test_t bv_dbl6
= {
494 "dbl -1e1000\n", "too large to express" };
495 static const badval_test_t bv_badcsvi1
=
496 { "csv_interval 10 wl\n", "malformed" };
497 static const badval_test_t bv_badcsvi2
=
498 { "csv_interval cl,10\n", "malformed" };
499 static const badval_test_t bv_nonoption
= { "fnord 10\n", "Unknown option" };
500 static const badval_test_t bv_badmem
= { "mem 3 trits\n", "malformed" };
501 static const badval_test_t bv_badbool
= { "boolean 7\n", "Unrecognized value"};
502 static const badval_test_t bv_badabool
=
503 { "autobool 7\n", "Unrecognized value" };
504 static const badval_test_t bv_badtime
= { "time lunchtime\n", "Invalid time" };
505 static const badval_test_t bv_virt
= { "MixedLines 7\n", "virtual option" };
506 static const badval_test_t bv_rs
= { "Routerset 2.2.2.2.2\n", "Invalid" };
507 static const badval_test_t bv_big_interval
=
508 { "interval 1000 months", "too large" };
510 /* Try config_dump(), and make sure it behaves correctly */
512 test_confparse_dump(void *arg
)
515 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
516 config_mgr_freeze(mgr
);
517 test_struct_t
*tst
= get_simple_config(mgr
);
520 /* Minimal version. */
521 dumped
= config_dump(mgr
, NULL
, tst
, 1, 0);
522 tt_str_op(dumped
, OP_EQ
,
525 "csv configuration,parsing,system\n"
528 "fn /simple/test of the\n"
537 "msec_interval 300000\n"
539 "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
541 "time 2019-06-14 13:58:51\n"
542 "u64 1000000000000\n");
545 dumped
= config_dump(mgr
, NULL
, tst
, 0, 0);
546 tt_str_op(dumped
, OP_EQ
,
549 "csv configuration,parsing,system\n"
553 "fn /simple/test of the\n"
562 "msec_interval 300000\n"
564 "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
566 "time 2019-06-14 13:58:51\n"
567 "u64 1000000000000\n");
571 dumped
= config_dump(mgr
, NULL
, tst
, 0, 1);
572 tt_str_op(dumped
, OP_EQ
,
575 "csv configuration,parsing,system\n"
578 "# deprecated_int 3\n"
579 "fn /simple/test of the\n"
588 "msec_interval 300000\n"
590 "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
592 "time 2019-06-14 13:58:51\n"
593 "u64 1000000000000\n");
596 config_free(mgr
, tst
);
598 config_mgr_free(mgr
);
601 /* Try confparse_reset_line(), and make sure it behaves correctly */
603 test_confparse_reset(void *arg
)
606 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
607 config_mgr_freeze(mgr
);
608 test_struct_t
*tst
= get_simple_config(mgr
);
610 config_reset_line(mgr
, tst
, "interval", 0);
611 tt_int_op(tst
->interval
, OP_EQ
, 0);
613 config_reset_line(mgr
, tst
, "interval", 1);
614 tt_int_op(tst
->interval
, OP_EQ
, 10);
616 tt_ptr_op(tst
->routerset
, OP_NE
, NULL
);
617 config_reset_line(mgr
, tst
, "routerset", 0);
618 tt_ptr_op(tst
->routerset
, OP_EQ
, NULL
);
621 config_free(mgr
, tst
);
622 config_mgr_free(mgr
);
625 /* Try setting options a second time on a config object, and make sure
626 * it behaves correctly. */
628 test_confparse_reassign(void *arg
)
631 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
632 config_mgr_freeze(mgr
);
633 test_struct_t
*tst
= get_simple_config(mgr
);
634 config_line_t
*lines
= NULL
;
635 char *msg
= NULL
, *rs
= NULL
;
637 int r
= config_get_lines(
642 "routerset 127.0.0.1\n",
644 r
= config_assign(mgr
, tst
,lines
, 0, &msg
);
645 tt_int_op(r
, OP_EQ
, 0);
646 tt_ptr_op(msg
, OP_EQ
, NULL
);
648 tt_str_op(tst
->s
, OP_EQ
, "eleven");
649 tt_str_op(tst
->fn
, OP_EQ
, "/simple/test of the"); // unchanged
650 tt_int_op(tst
->pos
, OP_EQ
, 77); // unchanged
651 tt_int_op(tst
->i
, OP_EQ
, 12);
652 tt_ptr_op(tst
->lines
, OP_NE
, NULL
);
653 tt_str_op(tst
->lines
->key
, OP_EQ
, "lines");
654 tt_str_op(tst
->lines
->value
, OP_EQ
, "13");
655 tt_ptr_op(tst
->lines
->next
, OP_EQ
, NULL
);
656 tt_int_op(smartlist_len(tst
->csv
), OP_EQ
, 2);
657 tt_str_op(smartlist_get(tst
->csv
, 0), OP_EQ
, "14");
658 tt_str_op(smartlist_get(tst
->csv
, 1), OP_EQ
, "15");
660 rs
= routerset_to_string(tst
->routerset
);
661 tt_str_op(rs
, OP_EQ
, "127.0.0.1");
663 // Try again with the CLEAR_FIRST and USE_DEFAULTS flags
664 r
= config_assign(mgr
, tst
, lines
,
665 CAL_CLEAR_FIRST
|CAL_USE_DEFAULTS
, &msg
);
666 tt_int_op(r
, OP_EQ
, 0);
668 tt_ptr_op(msg
, OP_EQ
, NULL
);
669 tt_str_op(tst
->s
, OP_EQ
, "eleven");
670 // tt_ptr_op(tst->fn, OP_EQ, NULL); //XXXX why is this not cleared?
671 // tt_int_op(tst->pos, OP_EQ, 0); //XXXX why is this not cleared?
672 tt_int_op(tst
->i
, OP_EQ
, 12);
675 config_free(mgr
, tst
);
676 config_free_lines(lines
);
679 config_mgr_free(mgr
);
682 /* Try setting options a second time on a config object, using the +foo
683 * linelist-extending syntax. */
685 test_confparse_reassign_extend(void *arg
)
688 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
689 config_mgr_freeze(mgr
);
690 test_struct_t
*tst
= get_simple_config(mgr
);
691 config_line_t
*lines
= NULL
;
694 int r
= config_get_lines(
696 &lines
, 1); // allow extended format.
697 tt_int_op(r
, OP_EQ
, 0);
698 r
= config_assign(mgr
, tst
,lines
, 0, &msg
);
699 tt_int_op(r
, OP_EQ
, 0);
700 tt_ptr_op(msg
, OP_EQ
, NULL
);
702 tt_assert(tst
->lines
);
703 tt_str_op(tst
->lines
->key
, OP_EQ
, "lines");
704 tt_str_op(tst
->lines
->value
, OP_EQ
, "hello");
705 tt_assert(tst
->lines
->next
);
706 tt_str_op(tst
->lines
->next
->key
, OP_EQ
, "lines");
707 tt_str_op(tst
->lines
->next
->value
, OP_EQ
, "world");
708 tt_assert(tst
->lines
->next
->next
);
709 tt_str_op(tst
->lines
->next
->next
->key
, OP_EQ
, "lines");
710 tt_str_op(tst
->lines
->next
->next
->value
, OP_EQ
, "13");
711 tt_assert(tst
->lines
->next
->next
->next
== NULL
);
712 config_free_lines(lines
);
714 r
= config_get_lines(
716 &lines
, 1); // allow extended format.
717 tt_int_op(r
, OP_EQ
, 0);
718 r
= config_assign(mgr
, tst
, lines
, 0, &msg
);
719 tt_int_op(r
, OP_EQ
, 0);
720 tt_ptr_op(msg
, OP_EQ
, NULL
);
721 tt_assert(tst
->lines
== NULL
);
722 config_free_lines(lines
);
724 config_free(mgr
, tst
);
725 tst
= get_simple_config(mgr
);
726 r
= config_get_lines(
728 &lines
, 1); // allow extended format.
729 tt_int_op(r
, OP_EQ
, 0);
730 r
= config_assign(mgr
, tst
, lines
, 0, &msg
);
731 tt_int_op(r
, OP_EQ
, 0);
732 tt_ptr_op(msg
, OP_EQ
, NULL
);
733 tt_assert(tst
->lines
== NULL
);
736 config_free(mgr
, tst
);
737 config_free_lines(lines
);
739 config_mgr_free(mgr
);
742 /* Test out confparse_get_assigned(). */
744 test_confparse_get_assigned(void *arg
)
748 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
749 config_mgr_freeze(mgr
);
750 test_struct_t
*tst
= get_simple_config(mgr
);
751 config_line_t
*lines
= NULL
;
753 lines
= config_get_assigned_option(mgr
, tst
, "I", 1);
755 tt_str_op(lines
->key
, OP_EQ
, "i");
756 tt_str_op(lines
->value
, OP_EQ
, "3");
757 tt_assert(lines
->next
== NULL
);
758 config_free_lines(lines
);
760 lines
= config_get_assigned_option(mgr
, tst
, "s", 1);
762 tt_str_op(lines
->key
, OP_EQ
, "s");
763 tt_str_op(lines
->value
, OP_EQ
, "this is a");
764 tt_assert(lines
->next
== NULL
);
765 config_free_lines(lines
);
767 lines
= config_get_assigned_option(mgr
, tst
, "obsolete", 1);
770 lines
= config_get_assigned_option(mgr
, tst
, "nonesuch", 1);
773 lines
= config_get_assigned_option(mgr
, tst
, "mixedlines", 1);
775 tt_str_op(lines
->key
, OP_EQ
, "LineTypeA");
776 tt_str_op(lines
->value
, OP_EQ
, "i d");
777 tt_assert(lines
->next
);
778 tt_str_op(lines
->next
->key
, OP_EQ
, "LineTypeB");
779 tt_str_op(lines
->next
->value
, OP_EQ
, "i c");
780 tt_assert(lines
->next
->next
== NULL
);
781 config_free_lines(lines
);
783 lines
= config_get_assigned_option(mgr
, tst
, "linetypeb", 1);
785 tt_str_op(lines
->key
, OP_EQ
, "LineTypeB");
786 tt_str_op(lines
->value
, OP_EQ
, "i c");
787 tt_assert(lines
->next
== NULL
);
788 config_free_lines(lines
);
791 tst
->s
= tor_strdup("Hello\nWorld");
792 lines
= config_get_assigned_option(mgr
, tst
, "s", 1);
794 tt_str_op(lines
->key
, OP_EQ
, "s");
795 tt_str_op(lines
->value
, OP_EQ
, "\"Hello\\nWorld\"");
796 tt_assert(lines
->next
== NULL
);
797 config_free_lines(lines
);
800 config_free(mgr
, tst
);
801 config_free_lines(lines
);
802 config_mgr_free(mgr
);
805 /* Another variant, which accepts and stores unrecognized lines.*/
806 #define ETEST_MAGIC 13371337
808 static struct_member_t extra
= {
810 .type
= CONFIG_TYPE_LINELIST
,
811 .offset
= offsetof(test_struct_t
, extra_lines
),
814 static config_format_t etest_fmt
= {
815 .size
= sizeof(test_struct_t
),
817 "test_struct_t (with extra lines)",
819 offsetof(test_struct_t
, magic
),
821 .abbrevs
= test_abbrevs
,
822 .deprecations
= test_deprecation_notes
,
824 .legacy_validate_fn
= test_validate_cb
,
828 /* Try out the feature where we can store unrecognized lines and dump them
829 * again. (State files use this.) */
831 test_confparse_extra_lines(void *arg
)
834 config_mgr_t
*mgr
= config_mgr_new(&etest_fmt
);
835 config_mgr_freeze(mgr
);
836 test_struct_t
*tst
= config_new(mgr
);
837 config_line_t
*lines
= NULL
;
838 char *msg
= NULL
, *dump
= NULL
;
840 config_init(mgr
, tst
);
842 int r
= config_get_lines(
845 "wombat knish\n", &lines
, 0);
846 tt_int_op(r
, OP_EQ
, 0);
847 r
= config_assign(mgr
, tst
, lines
, 0, &msg
);
848 tt_int_op(r
, OP_EQ
, 0);
849 tt_ptr_op(msg
, OP_EQ
, NULL
);
851 tt_assert(tst
->extra_lines
);
853 dump
= config_dump(mgr
, NULL
, tst
, 1, 0);
854 tt_str_op(dump
, OP_EQ
,
862 config_free_lines(lines
);
863 config_free(mgr
, tst
);
864 config_mgr_free(mgr
);
868 test_confparse_unitparse(void *args
)
871 /* spot-check a few memunit values. */
873 tt_u64_op(config_parse_memunit("100 MB", &ok
), OP_EQ
, 100<<20);
875 tt_u64_op(config_parse_memunit("100 TB", &ok
), OP_EQ
, UINT64_C(100)<<40);
877 // This is a floating-point value, but note that 1.5 can be represented
879 tt_u64_op(config_parse_memunit("1.5 MB", &ok
), OP_EQ
, 3<<19);
882 /* Try some good intervals and msec intervals */
883 tt_int_op(config_parse_interval("2 days", &ok
), OP_EQ
, 48*3600);
885 tt_int_op(config_parse_interval("1.5 hour", &ok
), OP_EQ
, 5400);
887 tt_u64_op(config_parse_interval("1 minute", &ok
), OP_EQ
, 60);
889 tt_int_op(config_parse_msec_interval("2 days", &ok
), OP_EQ
, 48*3600*1000);
891 tt_int_op(config_parse_msec_interval("10 msec", &ok
), OP_EQ
, 10);
894 /* Try a couple of unitless values. */
895 tt_int_op(config_parse_interval("10", &ok
), OP_EQ
, 10);
897 tt_u64_op(config_parse_interval("15.0", &ok
), OP_EQ
, 15);
901 tt_u64_op(config_parse_memunit("20000000 TB", &ok
), OP_EQ
, 0);
903 // This test fails the double check as the float representing 15000000.5 TB
904 // is greater than (double) INT64_MAX
905 tt_u64_op(config_parse_memunit("15000000.5 TB", &ok
), OP_EQ
, 0);
907 // 8388608.1 TB passes double check because it falls in the same float
908 // value as (double)INT64_MAX (which is 2^63) due to precision.
909 // But will fail the int check because the unsigned representation of
910 // the float, which is 2^63, is strictly greater than INT64_MAX (2^63-1)
911 tt_u64_op(config_parse_memunit("8388608.1 TB", &ok
), OP_EQ
, 0);
915 tt_u64_op(config_parse_memunit("-1.5 GB", &ok
), OP_EQ
, 0);
919 tt_int_op(config_parse_interval("1000 months", &ok
), OP_EQ
, -1);
921 tt_int_op(config_parse_msec_interval("4 weeks", &ok
), OP_EQ
, -1);
925 tt_u64_op(config_parse_memunit("7 nybbles", &ok
), OP_EQ
, 0);
927 // XXXX these next two should return -1 according to the documentation.
928 tt_int_op(config_parse_interval("7 cowznofski", &ok
), OP_EQ
, 0);
930 tt_int_op(config_parse_msec_interval("1 kalpa", &ok
), OP_EQ
, 0);
938 test_confparse_check_ok_fail(void *arg
)
941 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
942 config_mgr_freeze(mgr
);
943 test_struct_t
*tst
= config_new(mgr
);
945 tt_assert(! config_check_ok(mgr
, tst
, LOG_INFO
));
948 config_free(mgr
, tst
);
949 config_mgr_free(mgr
);
953 test_confparse_list_vars(void *arg
)
956 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
957 smartlist_t
*vars
= config_mgr_list_vars(mgr
);
958 smartlist_t
*varnames
= smartlist_new();
962 SMARTLIST_FOREACH(vars
, config_var_t
*, cv
,
963 smartlist_add(varnames
, (void*)cv
->member
.name
));
964 smartlist_sort_strings(varnames
);
965 joined
= smartlist_join_strings(varnames
, "::", 0, NULL
);
966 tt_str_op(joined
, OP_EQ
,
995 smartlist_free(varnames
);
996 smartlist_free(vars
);
997 config_mgr_free(mgr
);
1001 test_confparse_list_deprecated(void *arg
)
1004 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
1005 smartlist_t
*vars
= config_mgr_list_deprecated_vars(mgr
);
1006 char *joined
= NULL
;
1009 smartlist_sort_strings(vars
);
1010 joined
= smartlist_join_strings(vars
, "::", 0, NULL
);
1012 tt_str_op(joined
, OP_EQ
, "deprecated_int");
1016 smartlist_free(vars
);
1017 config_mgr_free(mgr
);
1021 test_confparse_find_option_name(void *arg
)
1024 config_mgr_t
*mgr
= config_mgr_new(&test_fmt
);
1027 tt_str_op(config_find_option_name(mgr
, "u64"), OP_EQ
, "u64");
1028 // case-insensitive match
1029 tt_str_op(config_find_option_name(mgr
, "S"), OP_EQ
, "s");
1030 tt_str_op(config_find_option_name(mgr
, "linetypea"), OP_EQ
, "LineTypeA");
1032 tt_str_op(config_find_option_name(mgr
, "deprec"), OP_EQ
, "deprecated_int");
1033 // explicit abbreviation
1034 tt_str_op(config_find_option_name(mgr
, "uint"), OP_EQ
, "pos");
1035 tt_str_op(config_find_option_name(mgr
, "UINT"), OP_EQ
, "pos");
1037 tt_ptr_op(config_find_option_name(mgr
, "absent"), OP_EQ
, NULL
);
1040 config_mgr_free(mgr
);
1044 #define CONFPARSE_TEST(name, flags) \
1045 { #name, test_confparse_ ## name, flags, NULL, NULL }
1047 #define BADVAL_TEST(name) \
1048 { "badval_" #name, test_confparse_assign_badval, 0, \
1049 &passthrough_setup, (void*)&bv_ ## name }
1050 #endif /* !defined(COCCI) */
1052 struct testcase_t confparse_tests
[] = {
1053 CONFPARSE_TEST(init
, 0),
1054 CONFPARSE_TEST(assign_simple
, 0),
1055 CONFPARSE_TEST(assign_obsolete
, 0),
1056 CONFPARSE_TEST(assign_deprecated
, 0),
1057 CONFPARSE_TEST(assign_replaced
, 0),
1058 CONFPARSE_TEST(assign_emptystring
, 0),
1059 CONFPARSE_TEST(assign_twice
, 0),
1060 BADVAL_TEST(notint
),
1061 BADVAL_TEST(negint
),
1062 BADVAL_TEST(badu64
),
1069 BADVAL_TEST(badcsvi1
),
1070 BADVAL_TEST(badcsvi2
),
1071 BADVAL_TEST(nonoption
),
1072 BADVAL_TEST(badmem
),
1073 BADVAL_TEST(badbool
),
1074 BADVAL_TEST(badabool
),
1075 BADVAL_TEST(badtime
),
1078 BADVAL_TEST(big_interval
),
1079 CONFPARSE_TEST(dump
, 0),
1080 CONFPARSE_TEST(reset
, 0),
1081 CONFPARSE_TEST(reassign
, 0),
1082 CONFPARSE_TEST(reassign_extend
, 0),
1083 CONFPARSE_TEST(get_assigned
, 0),
1084 CONFPARSE_TEST(extra_lines
, 0),
1085 CONFPARSE_TEST(unitparse
, 0),
1086 CONFPARSE_TEST(check_ok_fail
, 0),
1087 CONFPARSE_TEST(list_vars
, 0),
1088 CONFPARSE_TEST(list_deprecated
, 0),
1089 CONFPARSE_TEST(find_option_name
, 0),