1 /* ----------------------------------------------------------------------------
2 libconfig - A library for processing structured configuration files
3 Copyright (C) 2005-2018 Mark A Lindner
4
5 This file is part of libconfig.
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License
9 as published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with this library; if not, see
19 <http://www.gnu.org/licenses/>.
20 ----------------------------------------------------------------------------
21 */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <sys/stat.h>
26
27 #ifdef _MSC_VER
28 #define snprintf _snprintf
29 #endif
30
31 #include <libconfig.h>
32 #include <tinytest.h>
33
34 /* ------------------------------------------------------------------------- */
35
parse_and_compare(const char * input_file,const char * output_file)36 static void parse_and_compare(const char *input_file, const char *output_file)
37 {
38 config_t cfg;
39 int ok;
40
41 config_init(&cfg);
42 config_set_include_dir(&cfg, "./testdata");
43
44 ok = config_read_file(&cfg, input_file);
45 if(!ok)
46 {
47 printf("error: %s:%d\n", config_error_text(&cfg),
48 config_error_line(&cfg));
49 }
50 TT_ASSERT_TRUE(ok);
51
52 remove("temp.cfg");
53 TT_ASSERT_TRUE(config_write_file(&cfg, "temp.cfg"));
54
55 TT_ASSERT_TXTFILE_EQ("temp.cfg", output_file);
56 remove("temp.cfg");
57
58 config_destroy(&cfg);
59 }
60
61 /* ------------------------------------------------------------------------- */
62
parse_file_and_compare_error(const char * input_file,const char * parse_error)63 static void parse_file_and_compare_error(const char *input_file,
64 const char *parse_error)
65 {
66 config_t cfg;
67 char actual_error[128];
68 char expected_error[128];
69
70 config_init(&cfg);
71 TT_ASSERT_FALSE(config_read_file(&cfg, input_file));
72
73 snprintf(expected_error, sizeof(expected_error), "%s:%s",
74 input_file, parse_error);
75
76 snprintf(actual_error, sizeof(actual_error), "%s:%d %s\n",
77 config_error_file(&cfg), config_error_line(&cfg),
78 config_error_text(&cfg));
79
80 config_destroy(&cfg);
81
82 TT_ASSERT_STR_EQ(actual_error, expected_error);
83 }
84
85 /* ------------------------------------------------------------------------- */
86
parse_string_and_compare_error(const char * input_text,const char * parse_error)87 static void parse_string_and_compare_error(const char *input_text,
88 const char *parse_error)
89 {
90 config_t cfg;
91 char actual_error[128];
92 char expected_error[128];
93
94 config_init(&cfg);
95 TT_ASSERT_FALSE(config_read_string(&cfg, input_text));
96
97 snprintf(expected_error, sizeof(expected_error), "(null):%s", parse_error);
98
99 snprintf(actual_error, sizeof(actual_error), "%s:%d %s\n",
100 config_error_file(&cfg), config_error_line(&cfg),
101 config_error_text(&cfg));
102
103 config_destroy(&cfg);
104
105 TT_ASSERT_STR_EQ(actual_error, expected_error);
106 }
107
108 /* ------------------------------------------------------------------------- */
109
read_file_to_string(const char * file)110 static const char *read_file_to_string(const char *file)
111 {
112 struct stat stbuf;
113 FILE *fp;
114 int size;
115 char *buf;
116 size_t r;
117
118 TT_ASSERT_INT_EQ(0, stat(file, &stbuf));
119
120 size = stbuf.st_size;
121 buf = (char *)malloc(size + 1);
122 TT_ASSERT_PTR_NOTNULL(buf);
123
124 fp = fopen(file, "rt");
125 TT_ASSERT_PTR_NOTNULL(fp);
126
127 r = fread(buf, 1, size, fp);
128 fclose(fp);
129
130 TT_ASSERT_INT_EQ(size, r);
131
132 *(buf + size) = 0;
133 return(buf);
134 }
135
136 /* ------------------------------------------------------------------------- */
137
TT_TEST(ParsingAndFormatting)138 TT_TEST(ParsingAndFormatting)
139 {
140 int i;
141
142 for(i = 0;; ++i)
143 {
144 char input_file[128], output_file[128];
145 sprintf(input_file, "testdata/input_%d.cfg", i);
146 sprintf(output_file, "testdata/output_%d.cfg", i);
147 printf("parsing %s\n", input_file);
148
149 if(!tt_file_exists(input_file) || !tt_file_exists(output_file))
150 break;
151
152 parse_and_compare(input_file, output_file);
153 }
154 }
155
156 /* ------------------------------------------------------------------------- */
157
TT_TEST(ParseInvalidFiles)158 TT_TEST(ParseInvalidFiles)
159 {
160 int i;
161
162 for(i = 0;; ++i)
163 {
164 char input_file[128], error_file[128];
165 char error_text[128];
166 FILE *fp;
167
168 sprintf(input_file, "testdata/bad_input_%d.cfg", i);
169 sprintf(error_file, "testdata/parse_error_%d.txt", i);
170
171 if(!tt_file_exists(input_file) || !tt_file_exists(error_file))
172 break;
173
174 fp = fopen(error_file, "rt");
175 TT_ASSERT_PTR_NOTNULL(fp);
176 TT_ASSERT_PTR_NOTNULL(fgets(error_text, sizeof(error_text), fp));
177 fclose(fp);
178
179 parse_file_and_compare_error(input_file, error_text);
180 }
181 }
182
183 /* ------------------------------------------------------------------------- */
184
TT_TEST(ParseInvalidStrings)185 TT_TEST(ParseInvalidStrings)
186 {
187 int i;
188
189 for(i = 0;; ++i)
190 {
191 char input_file[128], error_file[128];
192 const char *input_text;
193 char error_text[128];
194 FILE *fp;
195
196 sprintf(input_file, "testdata/bad_input_%d.cfg", i);
197 sprintf(error_file, "testdata/parse_error_%d.txt", i);
198
199 if(!tt_file_exists(input_file) || !tt_file_exists(error_file))
200 break;
201
202 input_text = read_file_to_string(input_file);
203
204 fp = fopen(error_file, "rt");
205 TT_ASSERT_PTR_NOTNULL(fp);
206 TT_ASSERT_PTR_NOTNULL(fgets(error_text, sizeof(error_text), fp));
207 fclose(fp);
208
209 parse_string_and_compare_error(input_text, error_text);
210
211 free((void *)input_text);
212 }
213 }
214
215 /* ------------------------------------------------------------------------- */
216
TT_TEST(BigInt1)217 TT_TEST(BigInt1)
218 {
219 char *buf;
220 config_t cfg;
221 int rc;
222 int ival;
223 long long llval;
224
225 buf = "someint=5;";
226
227 config_init(&cfg);
228 rc = config_read_string(&cfg, buf);
229 TT_ASSERT_TRUE(rc);
230
231 rc = config_lookup_int(&cfg, "someint", &ival);
232 TT_ASSERT_TRUE(rc);
233 TT_ASSERT_INT_EQ(ival, 5);
234
235 rc = config_lookup_int64(&cfg, "someint", &llval);
236 TT_ASSERT_TRUE(rc);
237 TT_ASSERT_INT_EQ(llval, 5);
238
239 config_destroy(&cfg);
240 }
241
242 /* ------------------------------------------------------------------------- */
243
TT_TEST(BigInt2)244 TT_TEST(BigInt2)
245 {
246 char *buf;
247 config_t cfg;
248 int rc;
249 int ival = 123;
250 long long llval;
251
252 buf = "someint=8589934592;"; /* 2^33 */
253
254 config_init(&cfg);
255 rc = config_read_string(&cfg, buf);
256 TT_ASSERT_TRUE(rc);
257
258 /* Should fail because value was parsed as an int64. */
259 rc = config_lookup_int(&cfg, "someint", &ival);
260 TT_ASSERT_FALSE(rc);
261 TT_ASSERT_INT_EQ(ival, 123);
262
263 rc = config_lookup_int64(&cfg, "someint", &llval);
264 TT_ASSERT_TRUE(rc);
265 TT_ASSERT_INT64_EQ(llval, 8589934592LL);
266
267 config_destroy(&cfg);
268 }
269
270 /* ------------------------------------------------------------------------- */
271
TT_TEST(BigInt3)272 TT_TEST(BigInt3)
273 {
274 char *buf;
275 config_t cfg;
276 int rc;
277 int ival = 123;
278 long long llval;
279
280 buf = "someint=-8589934592;"; /* -2^33 */
281
282 config_init(&cfg);
283 rc = config_read_string(&cfg, buf);
284 TT_ASSERT_TRUE(rc);
285
286 /* Should fail because value was parsed as an int64. */
287 rc = config_lookup_int(&cfg, "someint", &ival);
288 TT_ASSERT_FALSE(rc);
289 TT_ASSERT_INT_EQ(ival, 123);
290
291 rc = config_lookup_int64(&cfg, "someint", &llval);
292 TT_ASSERT_TRUE(rc);
293 TT_ASSERT_INT64_EQ(llval, -8589934592LL);
294
295 config_destroy(&cfg);
296 }
297
298 /* ------------------------------------------------------------------------- */
299
TT_TEST(BigInt4)300 TT_TEST(BigInt4)
301 {
302 char *buf;
303 config_t cfg;
304 int rc;
305 int ival = 123;
306 long long llval;
307
308 buf = "someint=2147483647;"; /* 2^31-1 */
309
310 config_init(&cfg);
311 rc = config_read_string(&cfg, buf);
312 TT_ASSERT_TRUE(rc);
313
314 rc = config_lookup_int(&cfg, "someint", &ival);
315 TT_ASSERT_TRUE(rc);
316 TT_ASSERT_INT_EQ(ival, 2147483647);
317
318 rc = config_lookup_int64(&cfg, "someint", &llval);
319 TT_ASSERT_TRUE(rc);
320 TT_ASSERT_INT64_EQ(llval, 2147483647LL);
321
322 config_destroy(&cfg);
323 }
324
325 /* ------------------------------------------------------------------------- */
326
TT_TEST(BigInt5)327 TT_TEST(BigInt5)
328 {
329 char *buf;
330 config_t cfg;
331 int rc;
332 int ival = 123;
333 long long llval;
334
335 buf = "someint=2147483648;"; /* 2^31 */
336
337 config_init(&cfg);
338 rc = config_read_string(&cfg, buf);
339 TT_ASSERT_TRUE(rc);
340
341 /* Should fail because value was parsed as an int64. */
342 rc = config_lookup_int(&cfg, "someint", &ival);
343 TT_ASSERT_FALSE(rc);
344 TT_ASSERT_INT_EQ(ival, 123);
345
346 rc = config_lookup_int64(&cfg, "someint", &llval);
347 TT_ASSERT_TRUE(rc);
348 TT_ASSERT_INT64_EQ(llval, 2147483648LL);
349
350 config_destroy(&cfg);
351 }
352
353 /* ------------------------------------------------------------------------- */
354
TT_TEST(BigInt6)355 TT_TEST(BigInt6)
356 {
357 char *buf;
358 config_t cfg;
359 int rc;
360 int ival;
361 long long llval;
362
363 buf = "someint=-2147483648;"; /* -2^31 */
364
365 config_init(&cfg);
366 rc = config_read_string(&cfg, buf);
367 TT_ASSERT_TRUE(rc);
368
369 rc = config_lookup_int(&cfg, "someint", &ival);
370 TT_ASSERT_TRUE(rc);
371 TT_ASSERT_INT_EQ(ival, -2147483648LL);
372
373 rc = config_lookup_int64(&cfg, "someint", &llval);
374 TT_ASSERT_TRUE(rc);
375 TT_ASSERT_INT64_EQ(llval, -2147483648LL);
376
377 config_destroy(&cfg);
378 }
379
380 /* ------------------------------------------------------------------------- */
381
TT_TEST(BigInt7)382 TT_TEST(BigInt7)
383 {
384 char *buf;
385 config_t cfg;
386 int rc;
387 int ival = 123;
388 long long llval;
389
390 buf = "someint=-2147483649;"; /* -2^31-1 */
391
392 config_init(&cfg);
393 rc = config_read_string(&cfg, buf);
394 TT_ASSERT_TRUE(rc);
395
396 /* Should fail because value was parsed as an int64. */
397 rc = config_lookup_int(&cfg, "someint", &ival);
398 TT_ASSERT_FALSE(rc);
399 TT_ASSERT_INT_EQ(ival, 123);
400
401 rc = config_lookup_int64(&cfg, "someint", &llval);
402 TT_ASSERT_TRUE(rc);
403 TT_ASSERT_INT64_EQ(llval, -2147483649LL);
404
405 config_destroy(&cfg);
406 }
407
408 /* ------------------------------------------------------------------------- */
409
TT_TEST(RemoveSetting)410 TT_TEST(RemoveSetting)
411 {
412 char *buf;
413 config_t cfg;
414 int rc;
415 config_setting_t* rootSetting;
416
417 buf = "a:{b:3;c:4;}";
418
419 config_init(&cfg);
420 rc = config_read_string(&cfg, buf);
421 TT_ASSERT_TRUE(rc);
422
423 rootSetting = config_root_setting(&cfg);
424 rc = config_setting_remove(rootSetting, "a.c");
425 TT_ASSERT_TRUE(rc);
426
427 /* a and a.b are found */
428 rootSetting = config_lookup(&cfg, "a");
429 TT_EXPECT_PTR_NOTNULL(rootSetting);
430 rootSetting = config_lookup(&cfg, "a.b");
431 TT_EXPECT_PTR_NOTNULL(rootSetting);
432 rootSetting = config_lookup(&cfg, "a.c");
433 TT_EXPECT_PTR_NULL(rootSetting);
434
435 config_destroy(&cfg);
436 }
437
438 /* ------------------------------------------------------------------------- */
439
TT_TEST(EscapedStrings)440 TT_TEST(EscapedStrings)
441 {
442 config_t cfg;
443 int ok;
444 const char *str;
445
446 config_init(&cfg);
447 config_set_include_dir(&cfg, "./testdata");
448
449 ok = config_read_file(&cfg, "testdata/strings.cfg");
450 if(!ok)
451 {
452 printf("error: %s:%d\n", config_error_text(&cfg),
453 config_error_line(&cfg));
454 }
455 TT_ASSERT_TRUE(ok);
456
457 ok = config_lookup_string(&cfg, "escape_seqs.str", &str);
458 TT_ASSERT_TRUE(ok);
459 TT_ASSERT_STR_EQ("abc", str);
460
461 ok = config_lookup_string(&cfg, "escape_seqs.newline", &str);
462 TT_ASSERT_TRUE(ok);
463 TT_ASSERT_STR_EQ("abc\ndef\n", str);
464
465 ok = config_lookup_string(&cfg, "escape_seqs.cr", &str);
466 TT_ASSERT_TRUE(ok);
467 TT_ASSERT_STR_EQ("abc\rdef\r", str);
468
469 ok = config_lookup_string(&cfg, "escape_seqs.tab", &str);
470 TT_ASSERT_TRUE(ok);
471 TT_ASSERT_STR_EQ("abc\tdef\t", str);
472
473 ok = config_lookup_string(&cfg, "escape_seqs.feed", &str);
474 TT_ASSERT_TRUE(ok);
475 TT_ASSERT_STR_EQ("abc\fdef\f", str);
476
477 ok = config_lookup_string(&cfg, "escape_seqs.backslash", &str);
478 TT_ASSERT_TRUE(ok);
479 TT_ASSERT_STR_EQ("abc\\def\\", str);
480
481 ok = config_lookup_string(&cfg, "escape_seqs.dquote", &str);
482 TT_ASSERT_TRUE(ok);
483 TT_ASSERT_STR_EQ("abc\"def\"", str);
484
485 config_destroy(&cfg);
486 }
487
488 /* ------------------------------------------------------------------------- */
489
TT_TEST(OverrideSetting)490 TT_TEST(OverrideSetting)
491 {
492 config_t cfg;
493 int ok;
494 int ival;
495 const char *str;
496
497 config_init(&cfg);
498 config_set_options(&cfg, CONFIG_OPTION_ALLOW_OVERRIDES);
499 config_set_include_dir(&cfg, "./testdata");
500
501 ok = config_read_file(&cfg, "testdata/override_setting.cfg");
502 if(!ok)
503 {
504 printf("error: %s:%d\n", config_error_text(&cfg),
505 config_error_line(&cfg));
506 }
507 TT_ASSERT_TRUE(ok);
508
509 ok = config_lookup_string(&cfg, "group.message", &str);
510 TT_ASSERT_TRUE(ok);
511 TT_ASSERT_STR_EQ("overridden", str);
512
513 ok = config_lookup_string(&cfg, "group.inner.name", &str);
514 TT_ASSERT_TRUE(ok);
515 TT_ASSERT_STR_EQ("overridden", str);
516
517 ok = config_lookup_string(&cfg, "group.inner.other", &str);
518 TT_ASSERT_TRUE(ok);
519 TT_ASSERT_STR_EQ("other", str);
520
521 ok = config_lookup_string(&cfg, "group.inner.none", &str);
522 TT_ASSERT_FALSE(ok);
523
524 ok = config_lookup_string(&cfg, "group.inner.other", &str);
525 TT_ASSERT_TRUE(ok);
526 TT_ASSERT_STR_EQ("other", str);
527
528 ok = config_lookup_string(&cfg, "string", &str);
529 TT_ASSERT_TRUE(ok);
530 TT_ASSERT_STR_EQ("overridden", str);
531
532 ok = config_lookup_int(&cfg, "int", &ival);
533 TT_ASSERT_TRUE(ok);
534 TT_ASSERT_INT_EQ(ival, 2);
535
536 ok = config_lookup_int(&cfg, "group.array.[0]", &ival);
537 TT_ASSERT_TRUE(ok);
538 TT_ASSERT_INT_EQ(ival, 3);
539
540 ok = config_lookup_int(&cfg, "group.array.[1]", &ival);
541 TT_ASSERT_FALSE(ok);
542
543 config_destroy(&cfg);
544 }
545
546 /* ------------------------------------------------------------------------- */
547
main(int argc,char ** argv)548 int main(int argc, char **argv)
549 {
550 int failures;
551
552 TT_SUITE_START(LibConfigTests);
553 TT_SUITE_TEST(LibConfigTests, ParsingAndFormatting);
554 TT_SUITE_TEST(LibConfigTests, ParseInvalidFiles);
555 TT_SUITE_TEST(LibConfigTests, ParseInvalidStrings);
556 TT_SUITE_TEST(LibConfigTests, BigInt1);
557 TT_SUITE_TEST(LibConfigTests, BigInt2);
558 TT_SUITE_TEST(LibConfigTests, BigInt3);
559 TT_SUITE_TEST(LibConfigTests, BigInt4);
560 TT_SUITE_TEST(LibConfigTests, BigInt5);
561 TT_SUITE_TEST(LibConfigTests, BigInt6);
562 TT_SUITE_TEST(LibConfigTests, BigInt7);
563 TT_SUITE_TEST(LibConfigTests, RemoveSetting);
564 TT_SUITE_TEST(LibConfigTests, EscapedStrings);
565 TT_SUITE_TEST(LibConfigTests, OverrideSetting);
566 TT_SUITE_RUN(LibConfigTests);
567 failures = TT_SUITE_NUM_FAILURES(LibConfigTests);
568 TT_SUITE_END(LibConfigTests);
569
570 if (failures)
571 return EXIT_FAILURE;
572
573 return EXIT_SUCCESS;
574 }
575