1 /*
2 INI LIBRARY
3
4 Unit test for the value object.
5
6 Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
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 "config.h"
21 #include <errno.h> /* for errors */
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <limits.h>
27
28 #include "ini_valueobj.h"
29 #include "ini_defines.h"
30 #define TRACE_HOME
31 #include "trace.h"
32
33 #define TEST_SIZE 80
34
35 int verbose = 0;
36
37 #define VOOUT(foo) \
38 do { \
39 if (verbose) foo; \
40 } while(0)
41
42
43 typedef int (*test_fn)(void);
44
create_comment(int i,struct ini_comment ** ic)45 static int create_comment(int i, struct ini_comment **ic)
46 {
47 int error = EOK;
48 const char *template = ";Line 0 of the value %d";
49 char comment[TEST_SIZE];
50 struct ini_comment *new_ic = NULL;
51
52 TRACE_FLOW_ENTRY();
53
54 snprintf(comment, TEST_SIZE, template, i);
55
56
57 if ((error = ini_comment_create(&new_ic)) ||
58 (error = ini_comment_build(new_ic, comment)) ||
59 (error = ini_comment_build(new_ic, NULL)) ||
60 (error = ini_comment_build(new_ic, "#This is the second line")) ||
61 (error = ini_comment_build(new_ic, ";This is the third line")) ||
62 (error = ini_comment_build(new_ic, ""))) {
63 printf("Failed to create comment object. Error %d.\n", error);
64 ini_comment_destroy(new_ic);
65 return -1;
66 }
67
68 *ic = new_ic;
69
70 TRACE_FLOW_EXIT();
71 return EOK;
72 }
73
74 /* Save value to the file */
75 /* NOTE: might be moved into the API in future */
save_value(FILE * ff,const char * key,struct value_obj * vo)76 static int save_value(FILE *ff, const char *key, struct value_obj *vo)
77 {
78
79 int error = EOK;
80 struct simplebuffer *sbobj = NULL;
81 uint32_t left = 0;
82
83 TRACE_FLOW_ENTRY();
84
85 error = simplebuffer_alloc(&sbobj);
86 if (error) {
87 TRACE_ERROR_NUMBER("Failed to allocate dynamic string.", error);
88 return error;
89 }
90
91 /* Serialize */
92 error = value_serialize(vo, key, sbobj);
93 if (error) {
94 printf("Failed to serialize a value object %d.\n", error);
95 simplebuffer_free(sbobj);
96 return error;
97 }
98
99 /* Add CR */
100 error = simplebuffer_add_cr(sbobj);
101 if (error) {
102 TRACE_ERROR_NUMBER("Failed to add CR", error);
103 simplebuffer_free(sbobj);
104 return error;
105 }
106
107 /* Save */
108 left = simplebuffer_get_len(sbobj);
109 while (left > 0) {
110 error = simplebuffer_write(fileno(ff), sbobj, &left);
111 if (error) {
112 printf("Failed to write value object %d.\n", error);
113 simplebuffer_free(sbobj);
114 return error;
115 }
116 }
117
118 simplebuffer_free(sbobj);
119
120 TRACE_FLOW_EXIT();
121 return EOK;
122 }
123
124 /* Test to create value object using arrays */
other_create_test(FILE * ff,struct value_obj ** vo)125 static int other_create_test(FILE *ff, struct value_obj **vo)
126 {
127 int error = EOK;
128 struct value_obj *new_vo = NULL;
129 struct ref_array *raw_lines;
130 struct ref_array *raw_lengths;
131 struct ini_comment *ic = NULL;
132 struct ini_comment *ic2 = NULL;
133 char *val;
134 const char *vallines[] = { "Domain1,",
135 " Domain2 ,",
136 " Domain3 " };
137 const char *fullstr;
138 const char *expected = "Domain1, Domain2 , Domain3";
139 int i;
140 uint32_t origin = 0;
141 uint32_t line = 0;
142 uint32_t len = 0;
143 uint32_t expected_len = 0;
144
145
146 TRACE_FLOW_ENTRY();
147
148 /* Create a pair of arrays */
149 error = value_create_arrays(&raw_lines,
150 &raw_lengths);
151 if (error) {
152 printf("Failed to create arrays %d.\n", error);
153 return error;
154 }
155
156 for (i=0; i< 3; i++) {
157 errno = 0;
158 val = strdup(vallines[i]);
159 if (val == NULL) {
160 error = errno;
161 printf("Failed to dup memory %d.\n", error);
162 value_destroy_arrays(raw_lines,
163 raw_lengths);
164 return error;
165 }
166
167 /* Add line to the arrays */
168 error = value_add_to_arrays(val,
169 strlen(val),
170 raw_lines,
171 raw_lengths);
172 if (error) {
173 printf("Failed to add to arrays %d.\n", error);
174 value_destroy_arrays(raw_lines,
175 raw_lengths);
176 return error;
177 }
178
179 }
180
181 /* Create a comment */
182 error = create_comment(1000, &ic);
183 if (error) {
184 printf("Failed to create comment %d.\n", error);
185 value_destroy_arrays(raw_lines,
186 raw_lengths);
187 return error;
188 }
189
190 /* Create object */
191 error = value_create_from_refarray(raw_lines,
192 raw_lengths,
193 1,
194 INI_VALUE_READ,
195 3,
196 70,
197 ic,
198 &new_vo);
199
200 if (error) {
201 printf("Failed to create comment %d.\n", error);
202 value_destroy_arrays(raw_lines,
203 raw_lengths);
204 ini_comment_destroy(ic);
205 return error;
206 }
207
208 /* Save value to the file */
209 error = save_value(ff, "baz", new_vo);
210 if (error) {
211 printf("Failed to save value to file %d.\n", error);
212 value_destroy(new_vo);
213 return error;
214 }
215
216 /* Now do assertions and modifications to the object */
217
218 /* NOTE: Below this line do not need to free arrays or comment
219 * they became internal parts of the value object
220 * and will be freed as a part of it.
221 */
222
223 /* Get concatenated value */
224 error = value_get_concatenated(new_vo,
225 &fullstr);
226
227 if (error) {
228 printf("Failed to get the string %d.\n", error);
229 value_destroy(new_vo);
230 return error;
231 }
232
233 /* Get length of the concatenated value */
234 value_get_concatenated_len(new_vo, &len);
235 expected_len = strlen(expected);
236
237 if ((len != expected_len) ||
238 (strncmp(fullstr, expected, expected_len + 1) != 0)) {
239 printf("The expected value is different.\n");
240 printf("The expected value is %s\n", expected);
241 printf("The real value is %s\n", fullstr);
242 printf("The expected len is %d, real %d.\n", expected_len, len);
243 value_destroy(new_vo);
244 return EINVAL;
245 }
246
247 /* Get value's origin */
248 error = value_get_origin(new_vo, &origin);
249 if (error) {
250 printf("Failed to get origin %d.\n", error);
251 value_destroy(new_vo);
252 return error;
253 }
254
255 if (origin != INI_VALUE_READ) {
256 printf("The expected origin is different.\n%d\n", origin);
257 value_destroy(new_vo);
258 return EINVAL;
259 }
260
261 /* Get value's line */
262 error = value_get_line(new_vo, &line);
263 if (error) {
264 printf("Failed to get origin %d.\n", error);
265 value_destroy(new_vo);
266 return error;
267 }
268
269 if (line != 1) {
270 printf("The expected line is different.\n%d\n", origin);
271 value_destroy(new_vo);
272 return EINVAL;
273 }
274
275 /* Get comment from the value */
276 ic = NULL;
277 error = value_extract_comment(new_vo, &ic);
278 if (error) {
279 printf("Failed to extract comment %d.\n", error);
280 value_destroy(new_vo);
281 return error;
282 }
283
284 if (ic == NULL) {
285 printf("The expected comment to be there.\n");
286 value_destroy(new_vo);
287 return error;
288 }
289
290 VOOUT(ini_comment_print(ic, stdout));
291
292 /* Get comment again */
293 ic2 = NULL;
294 error = value_extract_comment(new_vo, &ic2);
295 if (error) {
296 printf("Failed to extract comment %d.\n", error);
297 value_destroy(new_vo);
298 ini_comment_destroy(ic);
299 return error;
300 }
301
302 if (ic2 != NULL) {
303 printf("The expected NO comment to be there.\n");
304 value_destroy(new_vo);
305 ini_comment_destroy(ic);
306 /* No free for ic2 since it is the same object */
307
308 /* But this should not happen anyways -
309 * it will be coding error.
310 */
311 return EINVAL;
312 }
313
314 /* Put comment back */
315 error = value_put_comment(new_vo, ic);
316 if (error) {
317 printf("Failed to put comment back %d.\n", error);
318 value_destroy(new_vo);
319 ini_comment_destroy(ic);
320 return error;
321 }
322
323 /* Save value to the file */
324 error = save_value(ff, "bar", new_vo);
325 if (error) {
326 printf("Failed to save value to file %d.\n", error);
327 value_destroy(new_vo);
328 return error;
329 }
330
331 *vo = new_vo;
332
333 TRACE_FLOW_EXIT();
334 return EOK;
335 }
336
337 /* Modify the value object */
modify_test(FILE * ff,struct value_obj * vo)338 static int modify_test(FILE *ff, struct value_obj *vo)
339 {
340 int error = EOK;
341 const char *strval = "Domain100, Domain200, Domain300";
342
343 TRACE_FLOW_ENTRY();
344
345
346 /* Update key length */
347 error = value_set_keylen(vo, strlen("foobar"));
348 if (error) {
349 printf("Failed to change key length %d.\n", error);
350 return error;
351 }
352
353 /* Update value */
354 error = value_update(vo,
355 strval,
356 strlen(strval),
357 INI_VALUE_CREATED,
358 10);
359 if (error) {
360 printf("Failed to update value %d.\n", error);
361 return error;
362 }
363
364
365 /* Save value to the file */
366 error = save_value(ff, "foobar", vo);
367 if (error) {
368 printf("Failed to save value to file %d.\n", error);
369 return error;
370 }
371
372 TRACE_FLOW_EXIT();
373 return EOK;
374 }
375
376
vo_basic_test(void)377 static int vo_basic_test(void)
378 {
379 int error = EOK;
380 const char *strvalue = "Test multi_word_value_that_will_"
381 "be_split_between_several_lines_!";
382
383 /* Other testing can be done with the following string:
384 * const char *strvalue = "Test multi word value that "
385 * "will be split between several lines";
386 */
387
388 struct value_obj *vo = NULL;
389 uint32_t wrap = 0;
390 struct ini_comment *ic = NULL;
391 FILE *ff = NULL;
392
393 TRACE_FLOW_ENTRY();
394
395 errno = 0;
396 ff = fopen("test.ini","wt");
397 if (ff == NULL) {
398 error = errno;
399 printf("Failed to open file. Error %d.\n", error);
400 return error;
401 }
402
403
404 for (wrap = 0; wrap < 80; wrap++) {
405
406 ic = NULL;
407 error = create_comment(wrap, &ic);
408 if (error) {
409 printf("Failed to create a new comment object %d.\n", error);
410 fclose(ff);
411 return error;
412 }
413
414 vo = NULL;
415 error = value_create_new(strvalue,
416 strlen(strvalue),
417 INI_VALUE_CREATED,
418 3,
419 wrap,
420 ic,
421 &vo);
422 if (error) {
423 printf("Failed to create a new value object %d.\n", error);
424 ini_comment_destroy(ic);
425 fclose(ff);
426 return error;
427 }
428
429 error = save_value(ff, "key", vo);
430 if (error) {
431 printf("Failed to save value to file %d.\n", error);
432 value_destroy(vo);
433 fclose(ff);
434 return error;
435 }
436
437 value_destroy(vo);
438 }
439
440 vo = NULL;
441
442 /* Run other create test here */
443 error = other_create_test(ff, &vo);
444 if (error) {
445 printf("Create test failed %d.\n", error);
446 fclose(ff);
447 return error;
448 }
449
450 /* Run modify test here */
451 error = modify_test(ff, vo);
452 if (error) {
453 printf("Modify test failed %d.\n", error);
454 fclose(ff);
455 value_destroy(vo);
456 return error;
457 }
458
459 value_destroy(vo);
460
461
462 ic = NULL;
463 error = create_comment(100, &ic);
464 if (error) {
465 printf("Failed to create a new comment object %d.\n", error);
466 fclose(ff);
467 return error;
468 }
469
470 ini_comment_print(ic, ff);
471
472 ini_comment_destroy(ic);
473
474 fclose(ff);
475
476 TRACE_FLOW_EXIT();
477 return EOK;
478 }
479
vo_copy_test(void)480 static int vo_copy_test(void)
481 {
482 int error = EOK;
483 const char *strvalue = "Test multi word value that "
484 "will be split between several lines";
485
486 struct value_obj *vo = NULL;
487 struct value_obj *vo_copy = NULL;
488 uint32_t wrap = 0;
489 struct ini_comment *ic = NULL;
490 FILE *ff = NULL;
491 char comment[100];
492
493 TRACE_FLOW_ENTRY();
494
495 VOOUT(printf("Copy test\n"));
496
497 errno = 0;
498 ff = fopen("test.ini","a");
499 if (ff == NULL) {
500 error = errno;
501 printf("Failed to open file. Error %d.\n", error);
502 return error;
503 }
504
505 error = ini_comment_create(&ic);
506 if (error) {
507 printf("Failed to create comment object\n");
508 fclose(ff);
509 return -1;
510 }
511
512 error = ini_comment_append(ic, "#This is a copy test!");
513 if (error) {
514 printf("Failed to add a line to the comment %d.\n", error);
515 ini_comment_destroy(ic);
516 fclose(ff);
517 return error;
518 }
519
520 error = ini_comment_append(ic, "#Replacable comment line");
521 if (error) {
522 printf("Failed to add a line to the comment %d.\n", error);
523 ini_comment_destroy(ic);
524 fclose(ff);
525 return error;
526 }
527
528 error = value_create_new(strvalue,
529 strlen(strvalue),
530 INI_VALUE_CREATED,
531 3,
532 20,
533 ic,
534 &vo);
535 if (error) {
536 printf("Failed to create a new value object %d.\n", error);
537 ini_comment_destroy(ic);
538 fclose(ff);
539 return error;
540 }
541
542 error = save_value(ff, "key", vo);
543 if (error) {
544 printf("Failed to save value to file %d.\n", error);
545 value_destroy(vo);
546 fclose(ff);
547 return error;
548 }
549
550 for (wrap = 0; wrap < 80; wrap++) {
551
552 TRACE_INFO_NUMBER("Iteration:", wrap);
553
554 vo_copy = NULL;
555 error = value_copy(vo, &vo_copy);
556 if (error) {
557 printf("Failed to create a new value object %d.\n", error);
558 value_destroy(vo);
559 fclose(ff);
560 return error;
561 }
562
563 error = value_set_boundary(vo_copy, wrap);
564 if (error) {
565 printf("Failed to set boundary %d.\n", error);
566 value_destroy(vo);
567 value_destroy(vo_copy);
568 fclose(ff);
569 return error;
570 }
571
572 /* Get comment from the value */
573 ic = NULL;
574 error = value_extract_comment(vo_copy, &ic);
575 if (error) {
576 printf("Failed to extract comment %d.\n", error);
577 value_destroy(vo);
578 value_destroy(vo_copy);
579 fclose(ff);
580 return error;
581 }
582
583 /* Replace comment in the value */
584 snprintf(comment, TEST_SIZE, ";This is value with boundary %d", wrap);
585 VOOUT(printf("Comment: %s\n", comment));
586 error = ini_comment_replace(ic, 1, comment);
587 if (error) {
588 printf("Failed to replace comment %d.\n", error);
589 value_destroy(vo);
590 value_destroy(vo_copy);
591 fclose(ff);
592 return error;
593 }
594
595 /* Set comment into the value */
596 error = value_put_comment(vo_copy, ic);
597 if (error) {
598 printf("Failed to set comment %d.\n", error);
599 value_destroy(vo);
600 value_destroy(vo_copy);
601 fclose(ff);
602 return error;
603 }
604
605 error = save_value(ff, "key", vo_copy);
606 if (error) {
607 printf("Failed to save value to file %d.\n", error);
608 value_destroy(vo);
609 value_destroy(vo_copy);
610 fclose(ff);
611 return error;
612 }
613
614 value_destroy(vo_copy);
615 }
616
617 value_destroy(vo);
618 fclose(ff);
619 TRACE_FLOW_EXIT();
620 return EOK;
621 }
622
vo_show_test(void)623 static int vo_show_test(void)
624 {
625 VOOUT(system("cat test.ini"));
626 return EOK;
627 }
628
vo_mc_test(void)629 static int vo_mc_test(void)
630 {
631 int error = EOK;
632 struct value_obj *vo1 = NULL;
633 struct value_obj *vo2 = NULL;
634 struct ini_comment *ic = NULL;
635
636 TRACE_FLOW_ENTRY();
637
638 VOOUT(printf("<=== Merge Comment Test ===>\n"));
639
640 error = create_comment(1, &ic);
641 if (error) {
642 printf("Failed to create a new comment object %d.\n", error);
643 return error;
644 }
645
646 error = value_create_new("test1",
647 5,
648 INI_VALUE_CREATED,
649 3,
650 80,
651 ic,
652 &vo1);
653 if (error) {
654 printf("Failed to create the first value object %d.\n", error);
655 ini_comment_destroy(ic);
656 return error;
657 }
658
659 error = create_comment(2, &ic);
660 if (error) {
661 printf("Failed to create a new comment object %d.\n", error);
662 value_destroy(vo1);
663 return error;
664 }
665
666 error = value_create_new("test2",
667 5,
668 INI_VALUE_CREATED,
669 3,
670 80,
671 ic,
672 &vo2);
673 if (error) {
674 printf("Failed to create the second value object %d.\n", error);
675 ini_comment_destroy(ic);
676 value_destroy(vo1);
677 return error;
678 }
679
680 /* Merge comment from one value into another */
681 error = value_merge_comment(vo2, vo1);
682 if (error) {
683 printf("Failed to merge comments %d.\n", error);
684 value_destroy(vo1);
685 value_destroy(vo2);
686 return error;
687 }
688
689 value_destroy(vo2);
690
691 VOOUT(printf("<=== Key ===>\n"));
692 VOOUT(value_print("key", vo1));
693
694 error = value_extract_comment(vo1, &ic);
695 if (error) {
696 printf("Failed to extract comment %d.\n", error);
697 value_destroy(vo1);
698 return error;
699 }
700
701 value_destroy(vo1);
702
703 VOOUT(printf("<=== Comment ===>\n"));
704 VOOUT(ini_comment_print(ic, stdout));
705 ini_comment_destroy(ic);
706
707 TRACE_FLOW_EXIT();
708 return EOK;
709 }
710
711
712 /* Main function of the unit test */
main(int argc,char * argv[])713 int main(int argc, char *argv[])
714 {
715 int error = 0;
716 test_fn tests[] = { vo_basic_test,
717 vo_copy_test,
718 vo_show_test,
719 vo_mc_test,
720 NULL };
721 test_fn t;
722 int i = 0;
723 char *var;
724
725 if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) verbose = 1;
726 else {
727 var = getenv("COMMON_TEST_VERBOSE");
728 if (var) verbose = 1;
729 }
730
731 VOOUT(printf("Start\n"));
732
733 while ((t = tests[i++])) {
734 error = t();
735 if (error) {
736 VOOUT(printf("Failed with error %d!\n", error));
737 return error;
738 }
739 }
740
741 VOOUT(printf("Success!\n"));
742 return 0;
743 }
744