Line data Source code
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 */
5 :
6 : /*
7 : * Tests for confmgt.c module that we use to parse various
8 : * configuration/state file types.
9 : */
10 :
11 : #define CONFMGT_PRIVATE
12 : #include "orconfig.h"
13 :
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"
20 :
21 : #include "lib/confmgt/unitparse.h"
22 :
23 : typedef struct test_struct_t {
24 : uint32_t magic;
25 : char *s;
26 : char *fn;
27 : int pos;
28 : int i;
29 : int deprecated_int;
30 : uint64_t u64;
31 : int interval;
32 : int msec_interval;
33 : uint64_t mem;
34 : double dbl;
35 : int boolean;
36 : int autobool;
37 : time_t time;
38 : smartlist_t *csv;
39 : int csv_interval;
40 : config_line_t *lines;
41 : config_line_t *mixed_lines;
42 : routerset_t *routerset;
43 : int hidden_int;
44 : config_line_t *mixed_hidden_lines;
45 :
46 : config_line_t *extra_lines;
47 : } test_struct_t;
48 :
49 : static test_struct_t test_struct_t_dummy;
50 :
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)
57 :
58 : static const config_var_t test_vars[] = {
59 : V(s, STRING, "hello"),
60 : V(fn, FILENAME, NULL),
61 : V(pos, POSINT, NULL),
62 : V(i, INT, "-10"),
63 : V(deprecated_int, INT, "3"),
64 : V(u64, UINT64, NULL),
65 : V(interval, INTERVAL, "10 seconds"),
66 : V(msec_interval, MSEC_INTERVAL, "150 msec"),
67 : V(mem, MEMUNIT, "10 MB"),
68 : V(dbl, DOUBLE, NULL),
69 : V(boolean, BOOL, "0"),
70 : V(autobool, AUTOBOOL, "auto"),
71 : V(time, ISOTIME, NULL),
72 : V(csv, CSV, 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),
78 : OBSOLETE("obsolete"),
79 : {
80 : .member = { .name = "routerset",
81 : .type = CONFIG_TYPE_EXTENDED,
82 : .type_def = &ROUTERSET_type_defn,
83 : .offset = offsetof(test_struct_t, routerset),
84 : },
85 : },
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),
90 :
91 : END_OF_CONFIG_VARS,
92 : };
93 :
94 : static config_abbrev_t test_abbrevs[] = {
95 : { "uint", "pos", 0, 0 },
96 : { "float", "dbl", 0, 1 },
97 : { NULL, NULL, 0, 0 }
98 : };
99 :
100 : static config_deprecation_t test_deprecation_notes[] = {
101 : { "deprecated_int", "This integer is deprecated." },
102 : { NULL, NULL }
103 : };
104 :
105 : static int
106 4 : test_validate_cb(const void *old_options, void *options, char **msg)
107 : {
108 4 : (void)old_options;
109 4 : (void)msg;
110 4 : test_struct_t *ts = options;
111 :
112 4 : if (ts->i == 0xbad) {
113 0 : *msg = tor_strdup("bad value for i");
114 0 : return -1;
115 : }
116 : return 0;
117 : }
118 :
119 : #define TEST_MAGIC 0x1337
120 :
121 : static const config_format_t test_fmt = {
122 : .size = sizeof(test_struct_t),
123 : .magic = {
124 : "test_struct_t",
125 : TEST_MAGIC,
126 : offsetof(test_struct_t, magic),
127 : },
128 : .abbrevs = test_abbrevs,
129 : .deprecations = test_deprecation_notes,
130 : .vars = test_vars,
131 : .legacy_validate_fn = test_validate_cb,
132 : };
133 :
134 : /* Make sure that config_init sets everything to the right defaults. */
135 : static void
136 1 : test_confparse_init(void *arg)
137 : {
138 1 : (void)arg;
139 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
140 1 : config_mgr_freeze(mgr);
141 1 : test_struct_t *tst = config_new(mgr);
142 1 : config_init(mgr, tst);
143 :
144 : // Make sure that options are initialized right. */
145 1 : tt_str_op(tst->s, OP_EQ, "hello");
146 1 : tt_ptr_op(tst->fn, OP_EQ, NULL);
147 1 : tt_int_op(tst->pos, OP_EQ, 0);
148 1 : tt_int_op(tst->i, OP_EQ, -10);
149 1 : tt_int_op(tst->deprecated_int, OP_EQ, 3);
150 1 : tt_u64_op(tst->u64, OP_EQ, 0);
151 1 : tt_int_op(tst->interval, OP_EQ, 10);
152 1 : tt_int_op(tst->msec_interval, OP_EQ, 150);
153 1 : tt_u64_op(tst->mem, OP_EQ, 10 * 1024 * 1024);
154 1 : tt_double_op(tst->dbl, OP_LT, .0000000001);
155 1 : tt_double_op(tst->dbl, OP_GT, -0.0000000001);
156 1 : tt_int_op(tst->boolean, OP_EQ, 0);
157 1 : tt_int_op(tst->autobool, OP_EQ, -1);
158 1 : tt_i64_op(tst->time, OP_EQ, 0);
159 1 : tt_ptr_op(tst->csv, OP_EQ, NULL);
160 1 : tt_int_op(tst->csv_interval, OP_EQ, 5);
161 1 : tt_ptr_op(tst->lines, OP_EQ, NULL);
162 1 : tt_ptr_op(tst->mixed_lines, OP_EQ, NULL);
163 1 : tt_int_op(tst->hidden_int, OP_EQ, 0);
164 :
165 1 : done:
166 1 : config_free(mgr, tst);
167 1 : config_mgr_free(mgr);
168 1 : }
169 :
170 : static const char simple_settings[] =
171 : "s this is a \n"
172 : "fn /simple/test of the\n"
173 : "uint 77\n" // this is an abbrev
174 : "i 3\n"
175 : "u64 1000000000000 \n"
176 : "interval 5 minutes \n"
177 : "msec_interval 5 minutes \n"
178 : "mem 10\n"
179 : "dbl 6.060842\n"
180 : "BOOLEAN 1\n"
181 : "aUtObOOl 0\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"
185 : "lines hello\n"
186 : "LINES world\n"
187 : "linetypea i d\n"
188 : "linetypeb i c\n"
189 : "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
190 : "__hiddenint 11\n"
191 : "__hiddenlineA XYZ\n"
192 : "visiblelineB ABC\n";
193 :
194 : /* Return a configuration object set up from simple_settings above. */
195 : static test_struct_t *
196 31 : get_simple_config(const config_mgr_t *mgr)
197 : {
198 31 : test_struct_t *result = NULL;
199 31 : test_struct_t *tst = config_new(mgr);
200 31 : config_line_t *lines = NULL;
201 31 : char *msg = NULL;
202 :
203 31 : config_init(mgr, tst);
204 :
205 31 : int r = config_get_lines(simple_settings, &lines, 0);
206 31 : tt_int_op(r, OP_EQ, 0);
207 31 : r = config_assign(mgr, tst, lines, 0, &msg);
208 31 : tt_int_op(r, OP_EQ, 0);
209 31 : tt_ptr_op(msg, OP_EQ, NULL);
210 :
211 : result = tst;
212 : tst = NULL; // prevent free
213 31 : done:
214 31 : tor_free(msg);
215 31 : config_free_lines(lines);
216 31 : config_free(mgr, tst);
217 31 : return result;
218 : }
219 :
220 : /* Make sure that config_assign can parse things. */
221 : static void
222 1 : test_confparse_assign_simple(void *arg)
223 : {
224 1 : (void)arg;
225 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
226 1 : config_mgr_freeze(mgr);
227 1 : test_struct_t *tst = get_simple_config(mgr);
228 :
229 1 : tt_str_op(tst->s, OP_EQ, "this is a");
230 1 : tt_str_op(tst->fn, OP_EQ, "/simple/test of the");
231 1 : tt_int_op(tst->pos, OP_EQ, 77);
232 1 : tt_int_op(tst->i, OP_EQ, 3);
233 1 : tt_int_op(tst->deprecated_int, OP_EQ, 3);
234 1 : tt_u64_op(tst->u64, OP_EQ, UINT64_C(1000000000000));
235 1 : tt_int_op(tst->interval, OP_EQ, 5 * 60);
236 1 : tt_int_op(tst->msec_interval, OP_EQ, 5 * 60 * 1000);
237 1 : tt_u64_op(tst->mem, OP_EQ, 10);
238 1 : tt_double_op(tst->dbl, OP_LT, 6.060843);
239 1 : tt_double_op(tst->dbl, OP_GT, 6.060841);
240 1 : tt_int_op(tst->boolean, OP_EQ, 1);
241 1 : tt_int_op(tst->autobool, OP_EQ, 0);
242 1 : tt_i64_op(tst->time, OP_EQ, 1560520731);
243 1 : tt_ptr_op(tst->csv, OP_NE, NULL);
244 1 : tt_int_op(smartlist_len(tst->csv), OP_EQ, 3);
245 1 : tt_str_op(smartlist_get(tst->csv, 0), OP_EQ, "configuration");
246 1 : tt_str_op(smartlist_get(tst->csv, 1), OP_EQ, "parsing");
247 1 : tt_str_op(smartlist_get(tst->csv, 2), OP_EQ, "system");
248 1 : tt_int_op(tst->csv_interval, OP_EQ, 10);
249 1 : tt_int_op(tst->hidden_int, OP_EQ, 11);
250 :
251 1 : tt_assert(tst->lines);
252 1 : tt_str_op(tst->lines->key, OP_EQ, "lines");
253 1 : tt_str_op(tst->lines->value, OP_EQ, "hello");
254 1 : tt_assert(tst->lines->next);
255 1 : tt_str_op(tst->lines->next->key, OP_EQ, "lines");
256 1 : tt_str_op(tst->lines->next->value, OP_EQ, "world");
257 1 : tt_assert(!tst->lines->next->next);
258 :
259 1 : tt_assert(tst->mixed_lines);
260 1 : tt_str_op(tst->mixed_lines->key, OP_EQ, "LineTypeA");
261 1 : tt_str_op(tst->mixed_lines->value, OP_EQ, "i d");
262 1 : tt_assert(tst->mixed_lines->next);
263 1 : tt_str_op(tst->mixed_lines->next->key, OP_EQ, "LineTypeB");
264 1 : tt_str_op(tst->mixed_lines->next->value, OP_EQ, "i c");
265 1 : tt_assert(!tst->mixed_lines->next->next);
266 :
267 1 : tt_assert(tst->mixed_hidden_lines);
268 1 : tt_str_op(tst->mixed_hidden_lines->key, OP_EQ, "__HiddenLineA");
269 1 : tt_str_op(tst->mixed_hidden_lines->value, OP_EQ, "XYZ");
270 1 : tt_assert(tst->mixed_hidden_lines->next);
271 1 : tt_str_op(tst->mixed_hidden_lines->next->key, OP_EQ, "VisibleLineB");
272 1 : tt_str_op(tst->mixed_hidden_lines->next->value, OP_EQ, "ABC");
273 1 : tt_assert(!tst->mixed_hidden_lines->next->next);
274 :
275 1 : tt_assert(config_check_ok(mgr, tst, LOG_ERR));
276 :
277 1 : done:
278 1 : config_free(mgr, tst);
279 1 : config_mgr_free(mgr);
280 1 : }
281 :
282 : /* Try to assign to an obsolete option, and make sure we get a warning. */
283 : static void
284 1 : test_confparse_assign_obsolete(void *arg)
285 : {
286 1 : (void)arg;
287 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
288 1 : config_mgr_freeze(mgr);
289 1 : test_struct_t *tst = get_simple_config(mgr);
290 1 : config_line_t *lines = NULL;
291 1 : char *msg = NULL;
292 :
293 1 : config_init(mgr, tst);
294 :
295 1 : int r = config_get_lines("obsolete option here",
296 : &lines, 0);
297 1 : tt_int_op(r, OP_EQ, 0);
298 1 : setup_capture_of_logs(LOG_WARN);
299 1 : r = config_assign(mgr, tst, lines, 0, &msg);
300 1 : tt_int_op(r, OP_EQ, 0);
301 1 : tt_ptr_op(msg, OP_EQ, NULL);
302 1 : expect_single_log_msg_containing("Skipping obsolete configuration option");
303 :
304 1 : done:
305 1 : teardown_capture_of_logs();
306 1 : config_free(mgr, tst);
307 1 : config_free_lines(lines);
308 1 : tor_free(msg);
309 1 : config_mgr_free(mgr);
310 1 : }
311 :
312 : /* Try to assign to an deprecated option, and make sure we get a warning
313 : * but the assignment works anyway. */
314 : static void
315 1 : test_confparse_assign_deprecated(void *arg)
316 : {
317 1 : (void)arg;
318 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
319 1 : config_mgr_freeze(mgr);
320 1 : test_struct_t *tst = get_simple_config(mgr);
321 1 : config_line_t *lines = NULL;
322 1 : char *msg = NULL;
323 :
324 1 : config_init(mgr, tst);
325 :
326 1 : int r = config_get_lines("deprecated_int 7",
327 : &lines, 0);
328 1 : tt_int_op(r, OP_EQ, 0);
329 1 : setup_capture_of_logs(LOG_WARN);
330 1 : r = config_assign(mgr, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
331 1 : tt_int_op(r, OP_EQ, 0);
332 1 : tt_ptr_op(msg, OP_EQ, NULL);
333 1 : expect_single_log_msg_containing("This integer is deprecated.");
334 :
335 1 : tt_int_op(tst->deprecated_int, OP_EQ, 7);
336 :
337 1 : tt_assert(config_check_ok(mgr, tst, LOG_ERR));
338 :
339 1 : done:
340 1 : teardown_capture_of_logs();
341 1 : config_free(mgr, tst);
342 1 : config_free_lines(lines);
343 1 : tor_free(msg);
344 1 : config_mgr_free(mgr);
345 1 : }
346 :
347 : /* Try to re-assign an option name that has been deprecated in favor of
348 : * another. */
349 : static void
350 1 : test_confparse_assign_replaced(void *arg)
351 : {
352 1 : (void)arg;
353 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
354 1 : config_mgr_freeze(mgr);
355 1 : test_struct_t *tst = get_simple_config(mgr);
356 1 : config_line_t *lines = NULL;
357 1 : char *msg = NULL;
358 :
359 1 : config_init(mgr, tst);
360 :
361 1 : int r = config_get_lines("float 1000\n", &lines, 0);
362 1 : tt_int_op(r, OP_EQ, 0);
363 1 : setup_capture_of_logs(LOG_WARN);
364 1 : r = config_assign(mgr, tst, lines, CAL_WARN_DEPRECATIONS, &msg);
365 1 : tt_int_op(r, OP_EQ, 0);
366 1 : tt_ptr_op(msg, OP_EQ, NULL);
367 1 : expect_single_log_msg_containing("use 'dbl' instead.");
368 :
369 1 : tt_double_op(tst->dbl, OP_GT, 999.999);
370 1 : tt_double_op(tst->dbl, OP_LT, 1000.001);
371 :
372 1 : done:
373 1 : teardown_capture_of_logs();
374 1 : config_free(mgr, tst);
375 1 : config_free_lines(lines);
376 1 : tor_free(msg);
377 1 : config_mgr_free(mgr);
378 1 : }
379 :
380 : /* Try to set a linelist value with no option. */
381 : static void
382 1 : test_confparse_assign_emptystring(void *arg)
383 : {
384 1 : (void)arg;
385 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
386 1 : config_mgr_freeze(mgr);
387 1 : test_struct_t *tst = get_simple_config(mgr);
388 1 : config_line_t *lines = NULL;
389 1 : char *msg = NULL;
390 :
391 1 : config_init(mgr, tst);
392 :
393 1 : int r = config_get_lines("lines\n", &lines, 0);
394 1 : tt_int_op(r, OP_EQ, 0);
395 1 : setup_capture_of_logs(LOG_WARN);
396 1 : r = config_assign(mgr, tst, lines, 0, &msg);
397 1 : tt_int_op(r, OP_EQ, 0);
398 1 : tt_ptr_op(msg, OP_EQ, NULL);
399 1 : expect_single_log_msg_containing("has no value");
400 :
401 1 : done:
402 1 : teardown_capture_of_logs();
403 1 : config_free(mgr, tst);
404 1 : config_free_lines(lines);
405 1 : tor_free(msg);
406 1 : config_mgr_free(mgr);
407 1 : }
408 :
409 : /* Try to set a the same option twice; make sure we get a warning. */
410 : static void
411 1 : test_confparse_assign_twice(void *arg)
412 : {
413 1 : (void)arg;
414 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
415 1 : config_mgr_freeze(mgr);
416 1 : test_struct_t *tst = get_simple_config(mgr);
417 1 : config_line_t *lines = NULL;
418 1 : char *msg = NULL;
419 :
420 1 : config_init(mgr, tst);
421 :
422 1 : int r = config_get_lines("pos 10\n"
423 : "pos 99\n", &lines, 0);
424 1 : tt_int_op(r, OP_EQ, 0);
425 1 : setup_capture_of_logs(LOG_WARN);
426 1 : r = config_assign(mgr, tst, lines, 0, &msg);
427 1 : tt_int_op(r, OP_EQ, 0);
428 1 : tt_ptr_op(msg, OP_EQ, NULL);
429 1 : expect_single_log_msg_containing("used more than once");
430 :
431 1 : done:
432 1 : teardown_capture_of_logs();
433 1 : config_free(mgr, tst);
434 1 : config_free_lines(lines);
435 1 : tor_free(msg);
436 1 : config_mgr_free(mgr);
437 1 : }
438 :
439 : typedef struct badval_test_t {
440 : const char *cfg;
441 : const char *expect_msg;
442 : } badval_test_t;
443 :
444 : /* Try to set an option and make sure that we get a failure and an expected
445 : * warning. */
446 : static void
447 19 : test_confparse_assign_badval(void *arg)
448 : {
449 19 : const badval_test_t *bt = arg;
450 19 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
451 19 : config_mgr_freeze(mgr);
452 19 : test_struct_t *tst = get_simple_config(mgr);
453 19 : config_line_t *lines = NULL;
454 19 : char *msg = NULL;
455 :
456 19 : config_init(mgr, tst);
457 :
458 19 : int r = config_get_lines(bt->cfg, &lines, 0);
459 19 : tt_int_op(r, OP_EQ, 0);
460 19 : setup_capture_of_logs(LOG_WARN);
461 19 : r = config_assign(mgr, tst, lines, 0, &msg);
462 19 : tt_int_op(r, OP_LT, 0);
463 19 : tt_ptr_op(msg, OP_NE, NULL);
464 19 : if (! strstr(msg, bt->expect_msg)) {
465 0 : TT_DIE(("'%s' did not contain '%s'" , msg, bt->expect_msg));
466 : }
467 :
468 19 : done:
469 19 : teardown_capture_of_logs();
470 19 : config_free(mgr, tst);
471 19 : config_free_lines(lines);
472 19 : tor_free(msg);
473 19 : config_mgr_free(mgr);
474 19 : }
475 :
476 : /* Various arguments for badval test.
477 : *
478 : * Note that the expected warnings here are _very_ truncated, since we
479 : * are writing these tests before a refactoring that we expect will
480 : * change them.
481 : */
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" };
509 :
510 : /* Try config_dump(), and make sure it behaves correctly */
511 : static void
512 1 : test_confparse_dump(void *arg)
513 : {
514 1 : (void)arg;
515 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
516 1 : config_mgr_freeze(mgr);
517 1 : test_struct_t *tst = get_simple_config(mgr);
518 1 : char *dumped = NULL;
519 :
520 : /* Minimal version. */
521 1 : dumped = config_dump(mgr, NULL, tst, 1, 0);
522 1 : tt_str_op(dumped, OP_EQ,
523 : "autobool 0\n"
524 : "boolean 1\n"
525 : "csv configuration,parsing,system\n"
526 : "csv_interval 10\n"
527 : "dbl 6.060842\n"
528 : "fn /simple/test of the\n"
529 : "i 3\n"
530 : "interval 300\n"
531 : "lines hello\n"
532 : "lines world\n"
533 : "mem 10\n"
534 : "VisibleLineB ABC\n"
535 : "LineTypeA i d\n"
536 : "LineTypeB i c\n"
537 : "msec_interval 300000\n"
538 : "pos 77\n"
539 : "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
540 : "s this is a\n"
541 : "time 2019-06-14 13:58:51\n"
542 : "u64 1000000000000\n");
543 :
544 1 : tor_free(dumped);
545 1 : dumped = config_dump(mgr, NULL, tst, 0, 0);
546 1 : tt_str_op(dumped, OP_EQ,
547 : "autobool 0\n"
548 : "boolean 1\n"
549 : "csv configuration,parsing,system\n"
550 : "csv_interval 10\n"
551 : "dbl 6.060842\n"
552 : "deprecated_int 3\n"
553 : "fn /simple/test of the\n"
554 : "i 3\n"
555 : "interval 300\n"
556 : "lines hello\n"
557 : "lines world\n"
558 : "mem 10\n"
559 : "VisibleLineB ABC\n"
560 : "LineTypeA i d\n"
561 : "LineTypeB i c\n"
562 : "msec_interval 300000\n"
563 : "pos 77\n"
564 : "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
565 : "s this is a\n"
566 : "time 2019-06-14 13:58:51\n"
567 : "u64 1000000000000\n");
568 :
569 : /* commented */
570 1 : tor_free(dumped);
571 1 : dumped = config_dump(mgr, NULL, tst, 0, 1);
572 1 : tt_str_op(dumped, OP_EQ,
573 : "autobool 0\n"
574 : "boolean 1\n"
575 : "csv configuration,parsing,system\n"
576 : "csv_interval 10\n"
577 : "dbl 6.060842\n"
578 : "# deprecated_int 3\n"
579 : "fn /simple/test of the\n"
580 : "i 3\n"
581 : "interval 300\n"
582 : "lines hello\n"
583 : "lines world\n"
584 : "mem 10\n"
585 : "VisibleLineB ABC\n"
586 : "LineTypeA i d\n"
587 : "LineTypeB i c\n"
588 : "msec_interval 300000\n"
589 : "pos 77\n"
590 : "routerset $FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF\n"
591 : "s this is a\n"
592 : "time 2019-06-14 13:58:51\n"
593 : "u64 1000000000000\n");
594 :
595 1 : done:
596 1 : config_free(mgr, tst);
597 1 : tor_free(dumped);
598 1 : config_mgr_free(mgr);
599 1 : }
600 :
601 : /* Try confparse_reset_line(), and make sure it behaves correctly */
602 : static void
603 1 : test_confparse_reset(void *arg)
604 : {
605 1 : (void)arg;
606 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
607 1 : config_mgr_freeze(mgr);
608 1 : test_struct_t *tst = get_simple_config(mgr);
609 :
610 1 : config_reset_line(mgr, tst, "interval", 0);
611 1 : tt_int_op(tst->interval, OP_EQ, 0);
612 :
613 1 : config_reset_line(mgr, tst, "interval", 1);
614 1 : tt_int_op(tst->interval, OP_EQ, 10);
615 :
616 1 : tt_ptr_op(tst->routerset, OP_NE, NULL);
617 1 : config_reset_line(mgr, tst, "routerset", 0);
618 1 : tt_ptr_op(tst->routerset, OP_EQ, NULL);
619 :
620 1 : done:
621 1 : config_free(mgr, tst);
622 1 : config_mgr_free(mgr);
623 1 : }
624 :
625 : /* Try setting options a second time on a config object, and make sure
626 : * it behaves correctly. */
627 : static void
628 1 : test_confparse_reassign(void *arg)
629 : {
630 1 : (void)arg;
631 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
632 1 : config_mgr_freeze(mgr);
633 1 : test_struct_t *tst = get_simple_config(mgr);
634 1 : config_line_t *lines = NULL;
635 1 : char *msg = NULL, *rs = NULL;
636 :
637 1 : int r = config_get_lines(
638 : "s eleven\n"
639 : "i 12\n"
640 : "lines 13\n"
641 : "csv 14,15\n"
642 : "routerset 127.0.0.1\n",
643 : &lines, 0);
644 1 : r = config_assign(mgr, tst,lines, 0, &msg);
645 1 : tt_int_op(r, OP_EQ, 0);
646 1 : tt_ptr_op(msg, OP_EQ, NULL);
647 :
648 1 : tt_str_op(tst->s, OP_EQ, "eleven");
649 1 : tt_str_op(tst->fn, OP_EQ, "/simple/test of the"); // unchanged
650 1 : tt_int_op(tst->pos, OP_EQ, 77); // unchanged
651 1 : tt_int_op(tst->i, OP_EQ, 12);
652 1 : tt_ptr_op(tst->lines, OP_NE, NULL);
653 1 : tt_str_op(tst->lines->key, OP_EQ, "lines");
654 1 : tt_str_op(tst->lines->value, OP_EQ, "13");
655 1 : tt_ptr_op(tst->lines->next, OP_EQ, NULL);
656 1 : tt_int_op(smartlist_len(tst->csv), OP_EQ, 2);
657 1 : tt_str_op(smartlist_get(tst->csv, 0), OP_EQ, "14");
658 1 : tt_str_op(smartlist_get(tst->csv, 1), OP_EQ, "15");
659 :
660 1 : rs = routerset_to_string(tst->routerset);
661 1 : tt_str_op(rs, OP_EQ, "127.0.0.1");
662 :
663 : // Try again with the CLEAR_FIRST and USE_DEFAULTS flags
664 1 : r = config_assign(mgr, tst, lines,
665 : CAL_CLEAR_FIRST|CAL_USE_DEFAULTS, &msg);
666 1 : tt_int_op(r, OP_EQ, 0);
667 :
668 1 : tt_ptr_op(msg, OP_EQ, NULL);
669 1 : 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 1 : tt_int_op(tst->i, OP_EQ, 12);
673 :
674 1 : done:
675 1 : config_free(mgr, tst);
676 1 : config_free_lines(lines);
677 1 : tor_free(msg);
678 1 : tor_free(rs);
679 1 : config_mgr_free(mgr);
680 1 : }
681 :
682 : /* Try setting options a second time on a config object, using the +foo
683 : * linelist-extending syntax. */
684 : static void
685 1 : test_confparse_reassign_extend(void *arg)
686 : {
687 1 : (void)arg;
688 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
689 1 : config_mgr_freeze(mgr);
690 1 : test_struct_t *tst = get_simple_config(mgr);
691 1 : config_line_t *lines = NULL;
692 1 : char *msg = NULL;
693 :
694 1 : int r = config_get_lines(
695 : "+lines 13\n",
696 : &lines, 1); // allow extended format.
697 1 : tt_int_op(r, OP_EQ, 0);
698 1 : r = config_assign(mgr, tst,lines, 0, &msg);
699 1 : tt_int_op(r, OP_EQ, 0);
700 1 : tt_ptr_op(msg, OP_EQ, NULL);
701 :
702 1 : tt_assert(tst->lines);
703 1 : tt_str_op(tst->lines->key, OP_EQ, "lines");
704 1 : tt_str_op(tst->lines->value, OP_EQ, "hello");
705 1 : tt_assert(tst->lines->next);
706 1 : tt_str_op(tst->lines->next->key, OP_EQ, "lines");
707 1 : tt_str_op(tst->lines->next->value, OP_EQ, "world");
708 1 : tt_assert(tst->lines->next->next);
709 1 : tt_str_op(tst->lines->next->next->key, OP_EQ, "lines");
710 1 : tt_str_op(tst->lines->next->next->value, OP_EQ, "13");
711 1 : tt_assert(tst->lines->next->next->next == NULL);
712 1 : config_free_lines(lines);
713 :
714 1 : r = config_get_lines(
715 : "/lines\n",
716 : &lines, 1); // allow extended format.
717 1 : tt_int_op(r, OP_EQ, 0);
718 1 : r = config_assign(mgr, tst, lines, 0, &msg);
719 1 : tt_int_op(r, OP_EQ, 0);
720 1 : tt_ptr_op(msg, OP_EQ, NULL);
721 1 : tt_assert(tst->lines == NULL);
722 1 : config_free_lines(lines);
723 :
724 1 : config_free(mgr, tst);
725 1 : tst = get_simple_config(mgr);
726 1 : r = config_get_lines(
727 : "/lines away!\n",
728 : &lines, 1); // allow extended format.
729 1 : tt_int_op(r, OP_EQ, 0);
730 1 : r = config_assign(mgr, tst, lines, 0, &msg);
731 1 : tt_int_op(r, OP_EQ, 0);
732 1 : tt_ptr_op(msg, OP_EQ, NULL);
733 1 : tt_assert(tst->lines == NULL);
734 :
735 1 : done:
736 1 : config_free(mgr, tst);
737 1 : config_free_lines(lines);
738 1 : tor_free(msg);
739 1 : config_mgr_free(mgr);
740 1 : }
741 :
742 : /* Test out confparse_get_assigned(). */
743 : static void
744 1 : test_confparse_get_assigned(void *arg)
745 : {
746 1 : (void)arg;
747 :
748 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
749 1 : config_mgr_freeze(mgr);
750 1 : test_struct_t *tst = get_simple_config(mgr);
751 1 : config_line_t *lines = NULL;
752 :
753 1 : lines = config_get_assigned_option(mgr, tst, "I", 1);
754 1 : tt_assert(lines);
755 1 : tt_str_op(lines->key, OP_EQ, "i");
756 1 : tt_str_op(lines->value, OP_EQ, "3");
757 1 : tt_assert(lines->next == NULL);
758 1 : config_free_lines(lines);
759 :
760 1 : lines = config_get_assigned_option(mgr, tst, "s", 1);
761 1 : tt_assert(lines);
762 1 : tt_str_op(lines->key, OP_EQ, "s");
763 1 : tt_str_op(lines->value, OP_EQ, "this is a");
764 1 : tt_assert(lines->next == NULL);
765 1 : config_free_lines(lines);
766 :
767 1 : lines = config_get_assigned_option(mgr, tst, "obsolete", 1);
768 1 : tt_assert(!lines);
769 :
770 1 : lines = config_get_assigned_option(mgr, tst, "nonesuch", 1);
771 1 : tt_assert(!lines);
772 :
773 1 : lines = config_get_assigned_option(mgr, tst, "mixedlines", 1);
774 1 : tt_assert(lines);
775 1 : tt_str_op(lines->key, OP_EQ, "LineTypeA");
776 1 : tt_str_op(lines->value, OP_EQ, "i d");
777 1 : tt_assert(lines->next);
778 1 : tt_str_op(lines->next->key, OP_EQ, "LineTypeB");
779 1 : tt_str_op(lines->next->value, OP_EQ, "i c");
780 1 : tt_assert(lines->next->next == NULL);
781 1 : config_free_lines(lines);
782 :
783 1 : lines = config_get_assigned_option(mgr, tst, "linetypeb", 1);
784 1 : tt_assert(lines);
785 1 : tt_str_op(lines->key, OP_EQ, "LineTypeB");
786 1 : tt_str_op(lines->value, OP_EQ, "i c");
787 1 : tt_assert(lines->next == NULL);
788 1 : config_free_lines(lines);
789 :
790 1 : tor_free(tst->s);
791 1 : tst->s = tor_strdup("Hello\nWorld");
792 1 : lines = config_get_assigned_option(mgr, tst, "s", 1);
793 1 : tt_assert(lines);
794 1 : tt_str_op(lines->key, OP_EQ, "s");
795 1 : tt_str_op(lines->value, OP_EQ, "\"Hello\\nWorld\"");
796 1 : tt_assert(lines->next == NULL);
797 1 : config_free_lines(lines);
798 :
799 1 : done:
800 1 : config_free(mgr, tst);
801 1 : config_free_lines(lines);
802 1 : config_mgr_free(mgr);
803 1 : }
804 :
805 : /* Another variant, which accepts and stores unrecognized lines.*/
806 : #define ETEST_MAGIC 13371337
807 :
808 : static struct_member_t extra = {
809 : .name = "__extra",
810 : .type = CONFIG_TYPE_LINELIST,
811 : .offset = offsetof(test_struct_t, extra_lines),
812 : };
813 :
814 : static config_format_t etest_fmt = {
815 : .size = sizeof(test_struct_t),
816 : .magic = {
817 : "test_struct_t (with extra lines)",
818 : ETEST_MAGIC,
819 : offsetof(test_struct_t, magic),
820 : },
821 : .abbrevs = test_abbrevs,
822 : .deprecations = test_deprecation_notes,
823 : .vars = test_vars,
824 : .legacy_validate_fn = test_validate_cb,
825 : .extra = &extra,
826 : };
827 :
828 : /* Try out the feature where we can store unrecognized lines and dump them
829 : * again. (State files use this.) */
830 : static void
831 1 : test_confparse_extra_lines(void *arg)
832 : {
833 1 : (void)arg;
834 1 : config_mgr_t *mgr = config_mgr_new(&etest_fmt);
835 1 : config_mgr_freeze(mgr);
836 1 : test_struct_t *tst = config_new(mgr);
837 1 : config_line_t *lines = NULL;
838 1 : char *msg = NULL, *dump = NULL;
839 :
840 1 : config_init(mgr, tst);
841 :
842 1 : int r = config_get_lines(
843 : "unknotty addita\n"
844 : "pos 99\n"
845 : "wombat knish\n", &lines, 0);
846 1 : tt_int_op(r, OP_EQ, 0);
847 1 : r = config_assign(mgr, tst, lines, 0, &msg);
848 1 : tt_int_op(r, OP_EQ, 0);
849 1 : tt_ptr_op(msg, OP_EQ, NULL);
850 :
851 1 : tt_assert(tst->extra_lines);
852 :
853 1 : dump = config_dump(mgr, NULL, tst, 1, 0);
854 1 : tt_str_op(dump, OP_EQ,
855 : "pos 99\n"
856 : "unknotty addita\n"
857 : "wombat knish\n");
858 :
859 1 : done:
860 1 : tor_free(msg);
861 1 : tor_free(dump);
862 1 : config_free_lines(lines);
863 1 : config_free(mgr, tst);
864 1 : config_mgr_free(mgr);
865 1 : }
866 :
867 : static void
868 1 : test_confparse_unitparse(void *args)
869 : {
870 1 : (void)args;
871 : /* spot-check a few memunit values. */
872 1 : int ok = 3;
873 1 : tt_u64_op(config_parse_memunit("100 MB", &ok), OP_EQ, 100<<20);
874 1 : tt_assert(ok);
875 1 : tt_u64_op(config_parse_memunit("100 TB", &ok), OP_EQ, UINT64_C(100)<<40);
876 1 : tt_assert(ok);
877 : // This is a floating-point value, but note that 1.5 can be represented
878 : // precisely.
879 1 : tt_u64_op(config_parse_memunit("1.5 MB", &ok), OP_EQ, 3<<19);
880 1 : tt_assert(ok);
881 :
882 : /* Try some good intervals and msec intervals */
883 1 : tt_int_op(config_parse_interval("2 days", &ok), OP_EQ, 48*3600);
884 1 : tt_assert(ok);
885 1 : tt_int_op(config_parse_interval("1.5 hour", &ok), OP_EQ, 5400);
886 1 : tt_assert(ok);
887 1 : tt_u64_op(config_parse_interval("1 minute", &ok), OP_EQ, 60);
888 1 : tt_assert(ok);
889 1 : tt_int_op(config_parse_msec_interval("2 days", &ok), OP_EQ, 48*3600*1000);
890 1 : tt_assert(ok);
891 1 : tt_int_op(config_parse_msec_interval("10 msec", &ok), OP_EQ, 10);
892 1 : tt_assert(ok);
893 :
894 : /* Try a couple of unitless values. */
895 1 : tt_int_op(config_parse_interval("10", &ok), OP_EQ, 10);
896 1 : tt_assert(ok);
897 1 : tt_u64_op(config_parse_interval("15.0", &ok), OP_EQ, 15);
898 1 : tt_assert(ok);
899 :
900 : /* u64 overflow */
901 1 : tt_u64_op(config_parse_memunit("20000000 TB", &ok), OP_EQ, 0);
902 1 : tt_assert(!ok);
903 : // This test fails the double check as the float representing 15000000.5 TB
904 : // is greater than (double) INT64_MAX
905 1 : tt_u64_op(config_parse_memunit("15000000.5 TB", &ok), OP_EQ, 0);
906 1 : tt_assert(!ok);
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 1 : tt_u64_op(config_parse_memunit("8388608.1 TB", &ok), OP_EQ, 0);
912 1 : tt_assert(!ok);
913 :
914 : /* negative float */
915 1 : tt_u64_op(config_parse_memunit("-1.5 GB", &ok), OP_EQ, 0);
916 1 : tt_assert(!ok);
917 :
918 : /* i32 overflow */
919 1 : tt_int_op(config_parse_interval("1000 months", &ok), OP_EQ, -1);
920 1 : tt_assert(!ok);
921 1 : tt_int_op(config_parse_msec_interval("4 weeks", &ok), OP_EQ, -1);
922 1 : tt_assert(!ok);
923 :
924 : /* bad units */
925 1 : tt_u64_op(config_parse_memunit("7 nybbles", &ok), OP_EQ, 0);
926 1 : tt_assert(!ok);
927 : // XXXX these next two should return -1 according to the documentation.
928 1 : tt_int_op(config_parse_interval("7 cowznofski", &ok), OP_EQ, 0);
929 1 : tt_assert(!ok);
930 1 : tt_int_op(config_parse_msec_interval("1 kalpa", &ok), OP_EQ, 0);
931 1 : tt_assert(!ok);
932 :
933 1 : done:
934 1 : ;
935 1 : }
936 :
937 : static void
938 1 : test_confparse_check_ok_fail(void *arg)
939 : {
940 1 : (void)arg;
941 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
942 1 : config_mgr_freeze(mgr);
943 1 : test_struct_t *tst = config_new(mgr);
944 1 : tst->pos = -10;
945 1 : tt_assert(! config_check_ok(mgr, tst, LOG_INFO));
946 :
947 1 : done:
948 1 : config_free(mgr, tst);
949 1 : config_mgr_free(mgr);
950 1 : }
951 :
952 : static void
953 1 : test_confparse_list_vars(void *arg)
954 : {
955 1 : (void)arg;
956 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
957 1 : smartlist_t *vars = config_mgr_list_vars(mgr);
958 1 : smartlist_t *varnames = smartlist_new();
959 1 : char *joined = NULL;
960 :
961 1 : tt_assert(vars);
962 26 : SMARTLIST_FOREACH(vars, config_var_t *, cv,
963 : smartlist_add(varnames, (void*)cv->member.name));
964 1 : smartlist_sort_strings(varnames);
965 1 : joined = smartlist_join_strings(varnames, "::", 0, NULL);
966 1 : tt_str_op(joined, OP_EQ,
967 : "LineTypeA::"
968 : "LineTypeB::"
969 : "MixedHiddenLines::"
970 : "MixedLines::"
971 : "VisibleLineB::"
972 : "__HiddenInt::"
973 : "__HiddenLineA::"
974 : "autobool::"
975 : "boolean::"
976 : "csv::"
977 : "csv_interval::"
978 : "dbl::"
979 : "deprecated_int::"
980 : "fn::"
981 : "i::"
982 : "interval::"
983 : "lines::"
984 : "mem::"
985 : "msec_interval::"
986 : "obsolete::"
987 : "pos::"
988 : "routerset::"
989 : "s::"
990 : "time::"
991 : "u64");
992 :
993 1 : done:
994 1 : tor_free(joined);
995 1 : smartlist_free(varnames);
996 1 : smartlist_free(vars);
997 1 : config_mgr_free(mgr);
998 1 : }
999 :
1000 : static void
1001 1 : test_confparse_list_deprecated(void *arg)
1002 : {
1003 1 : (void)arg;
1004 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
1005 1 : smartlist_t *vars = config_mgr_list_deprecated_vars(mgr);
1006 1 : char *joined = NULL;
1007 :
1008 1 : tt_assert(vars);
1009 1 : smartlist_sort_strings(vars);
1010 1 : joined = smartlist_join_strings(vars, "::", 0, NULL);
1011 :
1012 1 : tt_str_op(joined, OP_EQ, "deprecated_int");
1013 :
1014 1 : done:
1015 1 : tor_free(joined);
1016 1 : smartlist_free(vars);
1017 1 : config_mgr_free(mgr);
1018 1 : }
1019 :
1020 : static void
1021 1 : test_confparse_find_option_name(void *arg)
1022 : {
1023 1 : (void)arg;
1024 1 : config_mgr_t *mgr = config_mgr_new(&test_fmt);
1025 :
1026 : // exact match
1027 1 : tt_str_op(config_find_option_name(mgr, "u64"), OP_EQ, "u64");
1028 : // case-insensitive match
1029 1 : tt_str_op(config_find_option_name(mgr, "S"), OP_EQ, "s");
1030 1 : tt_str_op(config_find_option_name(mgr, "linetypea"), OP_EQ, "LineTypeA");
1031 : // prefix match
1032 1 : tt_str_op(config_find_option_name(mgr, "deprec"), OP_EQ, "deprecated_int");
1033 : // explicit abbreviation
1034 1 : tt_str_op(config_find_option_name(mgr, "uint"), OP_EQ, "pos");
1035 1 : tt_str_op(config_find_option_name(mgr, "UINT"), OP_EQ, "pos");
1036 : // no match
1037 1 : tt_ptr_op(config_find_option_name(mgr, "absent"), OP_EQ, NULL);
1038 :
1039 1 : done:
1040 1 : config_mgr_free(mgr);
1041 1 : }
1042 :
1043 : #ifndef COCCI
1044 : #define CONFPARSE_TEST(name, flags) \
1045 : { #name, test_confparse_ ## name, flags, NULL, NULL }
1046 :
1047 : #define BADVAL_TEST(name) \
1048 : { "badval_" #name, test_confparse_assign_badval, 0, \
1049 : &passthrough_setup, (void*)&bv_ ## name }
1050 : #endif /* !defined(COCCI) */
1051 :
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),
1063 : BADVAL_TEST(dbl1),
1064 : BADVAL_TEST(dbl2),
1065 : BADVAL_TEST(dbl3),
1066 : BADVAL_TEST(dbl4),
1067 : BADVAL_TEST(dbl5),
1068 : BADVAL_TEST(dbl6),
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),
1076 : BADVAL_TEST(virt),
1077 : BADVAL_TEST(rs),
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),
1090 : END_OF_TESTCASES
1091 : };
|