1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #include "cx/test.h"
30 #include "util_allocator.h"
31
32 #include "cx/properties.h"
33 #include "cx/hash_map.h"
34
35 CX_TEST(test_properties_init) {
36 CxProperties prop;
37 CX_TEST_DO {
38 cxPropertiesInitDefault(&prop);
39
40 CX_TEST_ASSERT(prop.config.delimiter ==
'=');
41 CX_TEST_ASSERT(prop.config.comment1 ==
'#');
42 CX_TEST_ASSERT(prop.config.comment2 ==
0);
43 CX_TEST_ASSERT(prop.config.comment3 ==
0);
44 CX_TEST_ASSERT(prop.config.continuation ==
'\\');
45 CX_TEST_ASSERT(prop.input.space ==
NULL);
46 CX_TEST_ASSERT(prop.buffer.space ==
NULL);
47
48 cxPropertiesDestroy(&prop);
49 }
50 }
51
52 CX_TEST(test_properties_next) {
53 const char *tests[] = {
54 "name = value\n",
55 "name=value\n",
56 "n=value\n",
57 "name=v\n",
58 "n=v\n",
59 "name = value # comment\n",
60 "#comment\nn=v\n",
61 "# comment1\n# comment2\n\n \n\nname = value\n",
62 " name = value\n",
63 "name = value\n\n"
64 };
65
66 const char *keys[] = {
67 "name",
68 "name",
69 "n",
70 "name",
71 "n",
72 "name",
73 "n",
74 "name",
75 "name",
76 "name"
77 };
78
79 const char *values[] = {
80 "value",
81 "value",
82 "value",
83 "v",
84 "v",
85 "value",
86 "v",
87 "value",
88 "value",
89 "value"
90 };
91
92 CxProperties prop;
93 cxPropertiesInitDefault(&prop);
94 CxPropertiesStatus result;
95 cxstring key;
96 cxstring value;
97 CX_TEST_DO {
98 for (
int i =
0; i <
10; i++) {
99 cxPropertiesFill(&prop, tests[i]);
100 CX_TEST_ASSERT(prop.input.space == tests[i]);
101 CX_TEST_ASSERT(prop.input.size == strlen(tests[i]));
102 CX_TEST_ASSERT(prop.input.pos ==
0);
103
104 result = cxPropertiesNext(&prop, &key, &value);
105 cxstring k = cx_str(keys[i]);
106 cxstring v = cx_str(values[i]);
107 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
108 CX_TEST_ASSERT(
0 == cx_strcmp(key, k));
109 CX_TEST_ASSERT(
0 == cx_strcmp(value, v));
110
111 result = cxPropertiesNext(&prop, &key, &value);
112 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_DATA);
113 }
114 }
115 cxPropertiesDestroy(&prop);
116 }
117
118 CX_TEST_SUBROUTINE(test_properties_next_multi_check, CxProperties *prop) {
119 const char *keys[] = {
120 "a",
121 "b",
122 "c",
123 "uap",
124 "name",
125 "key1",
126 "key2",
127 "key3"
128 };
129
130 const char *values[] = {
131 "a value",
132 "b value",
133 "core",
134 "core",
135 "ucx",
136 "value1",
137 "value2",
138 "value3"
139 };
140 CxPropertiesStatus result;
141 cxstring key;
142 cxstring value;
143 for (
int i =
0; i <
8; i++) {
144 result = cxPropertiesNext(prop, &key, &value);
145 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
146 CX_TEST_ASSERT(!cx_strcmp(key, cx_str(keys[i])));
147 CX_TEST_ASSERT(!cx_strcmp(value, cx_str(values[i])));
148 }
149 result = cxPropertiesNext(prop, &key, &value);
150 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_DATA);
151 }
152
153 CX_TEST(test_properties_next_multi) {
154 const char *str =
"#\n"
155 "# properties\n"
156 "# contains key/value pairs\n"
157 "#\n"
158 "a = a value\n"
159 "b = b value\n"
160 "c = core\n"
161 "\n# test\n"
162 "uap = core\n"
163 "name = ucx\n"
164 "# no = property\n"
165 "key1 = value1\n"
166 "#key1 = wrong value\n"
167 "#key2 = not value 2\n"
168 "key2 = value2\n"
169 "\n\n\n \n key3=value3\n";
170
171 CxProperties prop;
172 cxPropertiesInitDefault(&prop);
173
174 CX_TEST_DO {
175 CxPropertiesStatus result;
176 cxstring key;
177 cxstring value;
178 result = cxPropertiesNext(&prop, &key, &value);
179 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NULL_INPUT);
180
181
182 cxPropertiesFill(&prop, str);
183 CX_TEST_CALL_SUBROUTINE(test_properties_next_multi_check, &prop);
184
185
186 cxPropertiesFill(&prop, cx_str(str));
187 CX_TEST_CALL_SUBROUTINE(test_properties_next_multi_check, &prop);
188
189
190 cxPropertiesFill(&prop, cx_mutstr((
char*)str));
191 CX_TEST_CALL_SUBROUTINE(test_properties_next_multi_check, &prop);
192 }
193 cxPropertiesDestroy(&prop);
194 }
195
196 CX_TEST(test_properties_next_part) {
197 CxProperties prop;
198 cxPropertiesInitDefault(&prop);
199 CxPropertiesStatus result;
200 cxstring key;
201 cxstring value;
202 const char *str;
203
204 CX_TEST_DO {
205 str =
"";
206 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
207 result = cxPropertiesNext(&prop, &key, &value);
208 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_DATA);
209
210 str =
" \n";
211 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
212 result = cxPropertiesNext(&prop, &key, &value);
213 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_DATA);
214
215 str =
"name";
216 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
217 result = cxPropertiesNext(&prop, &key, &value);
218 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
219
220 str =
" ";
221 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
222 result = cxPropertiesNext(&prop, &key, &value);
223 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
224
225
226 str =
"= ";
227 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
228 str =
"value";
229 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
230 result = cxPropertiesNext(&prop, &key, &value);
231 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
232
233 str =
"\n";
234 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
235 result = cxPropertiesNext(&prop, &key, &value);
236 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
237 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"name")));
238 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"value")));
239
240
241 str =
"#comment\n";
242 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
243 result = cxPropertiesNext(&prop, &key, &value);
244 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_DATA);
245
246 str =
"#comment\nname2 = ";
247 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
248 result = cxPropertiesNext(&prop, &key, &value);
249 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
250
251 str =
"value2\na = b\n";
252 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
253 result = cxPropertiesNext(&prop, &key, &value);
254 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
255 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"name2")));
256 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"value2")));
257
258 result = cxPropertiesNext(&prop, &key, &value);
259 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
260 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"a")));
261 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"b")));
262
263 str =
"# comment\n#\n#\ntests = ";
264 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
265 result = cxPropertiesNext(&prop, &key, &value);
266 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
267
268 str =
"test1 ";
269 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
270 result = cxPropertiesNext(&prop, &key, &value);
271 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
272
273 str =
"test2 test3 test4\n";
274 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
275 result = cxPropertiesNext(&prop, &key, &value);
276 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
277 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"tests")));
278 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"test1 test2 test3 test4")));
279
280
281 str =
"# just a comment";
282 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
283 result = cxPropertiesNext(&prop, &key, &value);
284 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
285
286 str =
" in 3";
287 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
288 result = cxPropertiesNext(&prop, &key, &value);
289 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
290
291 str =
" parts\nx = 1\n";
292 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
293 result = cxPropertiesNext(&prop, &key, &value);
294 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
295 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"x")));
296 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"1")));
297
298
299 result = cxPropertiesNext(&prop, &key, &value);
300 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_DATA);
301 }
302 cxPropertiesDestroy(&prop);
303 }
304
305 CX_TEST(test_properties_next_long_lines) {
306 CxProperties prop;
307 cxPropertiesInitDefault(&prop);
308 CxPropertiesStatus result;
309 cxstring key;
310 cxstring value;
311
312 size_t key_len =
512;
313 char *long_key = (
char*)malloc(key_len);
314 memset(long_key,
'a',
70);
315 memset(long_key +
70,
'b',
242);
316 memset(long_key +
312,
'c',
200);
317
318 size_t value_len =
2048;
319 char *long_value = (
char*)malloc(value_len);
320 memset(long_value,
'x',
1024);
321 memset(long_value
+1024,
'y',
1024);
322
323 CX_TEST_DO {
324 cxPropertiesFilln(&prop, long_key,
10);
325 result = cxPropertiesNext(&prop, &key, &value);
326 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
327
328 cxPropertiesFilln(&prop, long_key +
10,
202);
329 result = cxPropertiesNext(&prop, &key, &value);
330 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
331
332 cxPropertiesFilln(&prop, long_key +
212,
200);
333 result = cxPropertiesNext(&prop, &key, &value);
334 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
335
336 cxPropertiesFilln(&prop, long_key +
412,
100);
337 result = cxPropertiesNext(&prop, &key, &value);
338 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
339
340 const char *str =
" = ";
341 cxPropertiesFill(&prop, str);
342 result = cxPropertiesNext(&prop, &key, &value);
343 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
344
345 cxPropertiesFilln(&prop, long_value,
512);
346 result = cxPropertiesNext(&prop, &key, &value);
347 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
348
349 cxPropertiesFilln(&prop, long_value +
512,
1024);
350 result = cxPropertiesNext(&prop, &key, &value);
351 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
352
353 cxPropertiesFilln(&prop, long_value +
1536,
512);
354 result = cxPropertiesNext(&prop, &key, &value);
355 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
356
357 str =
"\n#comment\nkey = value\n";
358 cxPropertiesFill(&prop, str);
359 result = cxPropertiesNext(&prop, &key, &value);
360 cxstring k = cx_strn(long_key, key_len);
361 cxstring v = cx_strn(long_value, value_len);
362 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
363 CX_TEST_ASSERT(
0 == cx_strcmp(key, k));
364 CX_TEST_ASSERT(
0 == cx_strcmp(value, v));
365
366 result = cxPropertiesNext(&prop, &key, &value);
367 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
368 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"key")));
369 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"value")));
370
371 result = cxPropertiesNext(&prop, &key, &value);
372 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_DATA);
373
374 CX_TEST_ASSERT(prop.buffer.capacity >
0);
375 CX_TEST_ASSERT(cxBufferEof(&prop.buffer));
376 CX_TEST_ASSERT(cxBufferEof(&prop.input));
377 cxPropertiesDestroy(&prop);
378 CX_TEST_ASSERT(prop.buffer.capacity ==
0);
379 CX_TEST_ASSERT(prop.buffer.size ==
0);
380 CX_TEST_ASSERT(prop.buffer.pos ==
0);
381 }
382
383 free(long_key);
384 free(long_value);
385 }
386
387 CX_TEST(test_properties_next_line_continuation) {
388 const char *str =
389 "key1 = multiline \\\nvalue\n"
390 "key2 = normal\n"
391 "key3 = multiline \\\n trim \n"
392 "key4 = m1\\\nm2\\\n m3\\\nm4 \n"
393 "key5 = no\\continuation\n"
394 "key6 = multiple \\\n \\\n \\\n continuations\n";
395
396 CxProperties prop;
397 cxPropertiesInitDefault(&prop);
398
399 cxstring key;
400 cxstring value;
401
402 CX_TEST_DO {
403 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
404
405 CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) ==
CX_PROPERTIES_NO_ERROR);
406 CX_TEST_ASSERT(!cx_strcmp(key,
"key1"));
407 CX_TEST_ASSERT(!cx_strcmp(value,
"multiline value"));
408
409 CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) ==
CX_PROPERTIES_NO_ERROR);
410 CX_TEST_ASSERT(!cx_strcmp(key,
"key2"));
411 CX_TEST_ASSERT(!cx_strcmp(value,
"normal"));
412
413 CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) ==
CX_PROPERTIES_NO_ERROR);
414 CX_TEST_ASSERT(!cx_strcmp(key,
"key3"));
415 CX_TEST_ASSERT(!cx_strcmp(value,
"multiline trim"));
416
417 CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) ==
CX_PROPERTIES_NO_ERROR);
418 CX_TEST_ASSERT(!cx_strcmp(key,
"key4"));
419 CX_TEST_ASSERT(!cx_strcmp(value,
"m1m2m3m4"));
420
421 CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) ==
CX_PROPERTIES_NO_ERROR);
422 CX_TEST_ASSERT(!cx_strcmp(key,
"key5"));
423 CX_TEST_ASSERT(!cx_strcmp(value,
"no\\continuation"));
424
425 CX_TEST_ASSERT(cxPropertiesNext(&prop, &key, &value) ==
CX_PROPERTIES_NO_ERROR);
426 CX_TEST_ASSERT(!cx_strcmp(key,
"key6"));
427 CX_TEST_ASSERT(!cx_strcmp(value,
"multiple continuations"));
428 }
429
430 cxPropertiesDestroy(&prop);
431 }
432
433 CX_TEST(test_properties_next_line_continuation_part) {
434 CxProperties prop;
435 cxPropertiesInitDefault(&prop);
436
437 cxstring key;
438 cxstring value;
439 CxPropertiesStatus result;
440 const char *str;
441
442 CX_TEST_DO {
443
444 str =
"key1 ";
445 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
446 result = cxPropertiesNext(&prop, &key, &value);
447 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
448
449 str =
"= continue \\";
450 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
451 result = cxPropertiesNext(&prop, &key, &value);
452 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
453
454 str =
"\ncontinue \\\n";
455 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
456 result = cxPropertiesNext(&prop, &key, &value);
457 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
458
459 str =
"...";
460 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
461 result = cxPropertiesNext(&prop, &key, &value);
462 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
463
464 str =
"line\nkey2 = value2\n";
465 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, str));
466 result = cxPropertiesNext(&prop, &key, &value);
467 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
468 CX_TEST_ASSERT(!cx_strcmp(key,
"key1"));
469 CX_TEST_ASSERT(!cx_strcmp(value,
"continue continue ...line"));
470
471
472 result = cxPropertiesNext(&prop, &key, &value);
473 CX_TEST_ASSERT(!cx_strcmp(key,
"key2"));
474 CX_TEST_ASSERT(!cx_strcmp(value,
"value2"));
475
476
477 str =
"key3=\\\ncontinue-\\\n line";
478 size_t len = strlen(str);
479 for(
size_t i=
0;i<len;i++) {
480 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop, cx_strn(str+i,
1)));
481 result = cxPropertiesNext(&prop, &key, &value);
482 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
483 }
484 CX_TEST_ASSERT(
0 == cxPropertiesFill(&prop,
"\n"));
485 result = cxPropertiesNext(&prop, &key, &value);
486 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
487 CX_TEST_ASSERT(!cx_strcmp(key,
"key3"));
488 CX_TEST_ASSERT(!cx_strcmp(value,
"continue-line"));
489 }
490
491 cxPropertiesDestroy(&prop);
492 }
493
494 CX_TEST(test_properties_load) {
495 CxTestingAllocator talloc;
496 cx_testing_allocator_init(&talloc);
497 char fname[
16] =
"ucxtestXXXXXX";
498 int tmpfd = mkstemp(fname);
499 FILE *f = tmpfd <
0 ?
NULL : fdopen(tmpfd,
"w");
500 CX_TEST_DO {
501 CX_TEST_ASSERTM(f,
"test file cannot be opened, test aborted");
502 fprintf(f,
"# properties file\n\nkey1 = value1\nkey2 = value2\n");
503 fprintf(f,
"\n\nkey3 = value3\n\n");
504
505 size_t key_len =
512;
506 char *long_key = (
char *) malloc(key_len);
507 memset(long_key,
'k',
512);
508
509 size_t value_len =
2048;
510 char *long_value = (
char *) malloc(value_len);
511 memset(long_value,
'v',
2048);
512
513 fwrite(long_key,
1, key_len, f);
514 fprintf(f,
" = ");
515 fwrite(long_value,
1, value_len, f);
516 fprintf(f,
" \n");
517
518 fprintf(f,
"\n\n\n\nlast_key = property value\n");
519 fclose(f);
520 f =
NULL;
521
522
523
524 CxMap *map = cxHashMapCreateSimple(
CX_STORE_POINTERS);
525 cxDefineAdvancedDestructor(map, cxFree, &talloc);
526 CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
527
528 CX_TEST_ASSERT(status ==
CX_PROPERTIES_NO_ERROR);
529 CX_TEST_ASSERT(cxMapSize(map) ==
5);
530
531 char *v1 = cxMapGet(map,
"key1");
532 char *v2 = cxMapGet(map, cx_str(
"key2"));
533 char *v3 = cxMapGet(map,
"key3");
534 char *lv = cxMapGet(map, cx_strn(long_key, key_len));
535 char *lk = cxMapGet(map,
"last_key");
536
537 CX_TEST_ASSERTM(v1,
"value for key1 not found");
538 CX_TEST_ASSERTM(v2,
"value for key2 not found");
539 CX_TEST_ASSERTM(v3,
"value for key3 not found");
540 CX_TEST_ASSERTM(lv,
"value for long key not found");
541 CX_TEST_ASSERTM(lk,
"value for last_key not found");
542
543 CX_TEST_ASSERT(!strcmp(v1,
"value1"));
544 CX_TEST_ASSERT(!strcmp(v2,
"value2"));
545 CX_TEST_ASSERT(!strcmp(v3,
"value3"));
546 cxstring expected = cx_strn(long_value, value_len);
547 cxstring actual = cx_str(lv);
548 CX_TEST_ASSERT(!cx_strcmp(expected, actual));
549 CX_TEST_ASSERT(!strcmp(lk,
"property value"));
550
551 free(long_key);
552 free(long_value);
553 CX_TEST_ASSERT(cx_testing_allocator_used(&talloc));
554 cxMapFree(map);
555 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
556 }
557 cx_testing_allocator_destroy(&talloc);
558 if (f) fclose(f);
559 remove(fname);
560 }
561
562 CX_TEST(test_properties_load_empty_file) {
563 CxTestingAllocator talloc;
564 cx_testing_allocator_init(&talloc);
565 char fname[
16] =
"ucxtestXXXXXX";
566 int tmpfd = mkstemp(fname);
567 FILE *f = tmpfd <
0 ?
NULL : fdopen(tmpfd,
"w");
568 CX_TEST_DO {
569 CX_TEST_ASSERTM(f,
"test file cannot be opened, test aborted");
570 fclose(f);
571 f =
NULL;
572
573 CxMap *map = cxHashMapCreateSimple(
CX_STORE_POINTERS);
574
575 cxMapPut(map,
"test",
"value");
576 CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
577 CX_TEST_ASSERT(status ==
CX_PROPERTIES_NO_DATA);
578 CX_TEST_ASSERT(cxMapSize(map) ==
1);
579
580 char *v = cxMapGet(map,
"test");
581 CX_TEST_ASSERTM(v,
"value was removed");
582 CX_TEST_ASSERT(!strcmp(v,
"value"));
583 CX_TEST_ASSERT(!cx_testing_allocator_used(&talloc));
584 cxMapFree(map);
585 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
586 }
587 cx_testing_allocator_destroy(&talloc);
588 if (f) fclose(f);
589 remove(fname);
590 }
591
592 CX_TEST(test_properties_load_only_comments) {
593 CxTestingAllocator talloc;
594 cx_testing_allocator_init(&talloc);
595 char fname[
16] =
"ucxtestXXXXXX";
596 int tmpfd = mkstemp(fname);
597 FILE *f = tmpfd <
0 ?
NULL : fdopen(tmpfd,
"w");
598 CX_TEST_DO {
599 CX_TEST_ASSERTM(f,
"test file cannot be opened, test aborted");
600 fputs(
"# test file\n\n# contains only comments\n\n# key = value\n", f);
601 fclose(f);
602 f =
NULL;
603
604 CxMap *map = cxHashMapCreateSimple(
CX_STORE_POINTERS);
605 CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
606 CX_TEST_ASSERT(status ==
CX_PROPERTIES_NO_DATA);
607 CX_TEST_ASSERT(cxMapSize(map) ==
0);
608
609 CX_TEST_ASSERT(!cx_testing_allocator_used(&talloc));
610 cxMapFree(map);
611 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
612 }
613 cx_testing_allocator_destroy(&talloc);
614 if (f) fclose(f);
615 remove(fname);
616 }
617
618 CX_TEST(test_properties_load_error) {
619 CxTestingAllocator talloc;
620 cx_testing_allocator_init(&talloc);
621 char fname[
16] =
"ucxtestXXXXXX";
622 int tmpfd = mkstemp(fname);
623 FILE *f = tmpfd <
0 ?
NULL : fdopen(tmpfd,
"w");
624 CX_TEST_DO {
625 CX_TEST_ASSERTM(f,
"test file cannot be opened, test aborted");
626 fputs(
"# test file\n\ntest = value\n = value2\n", f);
627 fclose(f);
628 f =
NULL;
629
630 CxMap *map = cxHashMapCreateSimple(
CX_STORE_POINTERS);
631 cxDefineAdvancedDestructor(map, cxFree, &talloc);
632 CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
633 CX_TEST_ASSERT(status ==
CX_PROPERTIES_INVALID_EMPTY_KEY);
634
635 CX_TEST_ASSERT(cxMapSize(map) ==
1);
636 char *v = cxMapGet(map,
"test");
637 CX_TEST_ASSERT(v !=
NULL);
638 CX_TEST_ASSERT(!strcmp(v,
"value"));
639
640 cxMapFree(map);
641 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
642 }
643 cx_testing_allocator_destroy(&talloc);
644 if (f) fclose(f);
645 remove(fname);
646 }
647
648 CX_TEST(test_properties_load_file_not_exists) {
649 CX_TEST_DO {
650 CxMap *map = cxHashMapCreateSimple(
CX_STORE_POINTERS);
651 CxPropertiesStatus status = cxPropertiesLoadDefault(
NULL,
"does-definitely-not-exist", map);
652 CX_TEST_ASSERT(status ==
CX_PROPERTIES_FILE_ERROR);
653 cxMapFree(map);
654 }
655 }
656
657 CX_TEST(test_properties_load_cxmutstr_map) {
658 CxTestingAllocator talloc;
659 cx_testing_allocator_init(&talloc);
660 char fname[
16] =
"ucxtestXXXXXX";
661 int tmpfd = mkstemp(fname);
662 FILE *f = tmpfd <
0 ?
NULL : fdopen(tmpfd,
"w");
663 CX_TEST_DO {
664 CX_TEST_ASSERTM(f,
"test file cannot be opened, test aborted");
665 fputs(
"# test file\n\ntest = value\ntest2 = value2\n", f);
666 fclose(f);
667 f =
NULL;
668
669 CxMap *map = cxHashMapCreateSimple(
sizeof(cxmutstr));
670 cxDefineAdvancedDestructor(map, cx_strfree_a, &talloc);
671 CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
672 CX_TEST_ASSERT(status ==
CX_PROPERTIES_NO_ERROR);
673 CX_TEST_ASSERT(cxMapSize(map) ==
2);
674 cxstring v1 =
CX_STR(
"value");
675 cxstring v2 =
CX_STR(
"value2");
676 CX_TEST_ASSERT(cx_strcmp_p(cxMapGet(map,
"test"), &v1) ==
0);
677 CX_TEST_ASSERT(cx_strcmp_p(cxMapGet(map,
"test2"), &v2) ==
0);
678
679 CX_TEST_ASSERT(cx_testing_allocator_used(&talloc));
680 cxMapFree(map);
681 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
682 }
683 cx_testing_allocator_destroy(&talloc);
684 if (f) fclose(f);
685 remove(fname);
686 }
687
688 CX_TEST(test_properties_load_incompatible_map) {
689 CxTestingAllocator talloc;
690 cx_testing_allocator_init(&talloc);
691 char fname[
16] =
"ucxtestXXXXXX";
692 int tmpfd = mkstemp(fname);
693 FILE *f = tmpfd <
0 ?
NULL : fdopen(tmpfd,
"w");
694 CX_TEST_DO {
695 CX_TEST_ASSERTM(f,
"test file cannot be opened, test aborted");
696 fputs(
"# test file\n\ntest = value\ntest2 = value2\n", f);
697 fclose(f);
698 f =
NULL;
699
700 CxMap *map = cxHashMapCreateSimple(
sizeof(CxBuffer));
701 cxDefineAdvancedDestructor(map, cxFree, &talloc);
702 CxPropertiesStatus status = cxPropertiesLoadDefault(&talloc.base, fname, map);
703 CX_TEST_ASSERT(status ==
CX_PROPERTIES_MAP_ERROR);
704 CX_TEST_ASSERT(cxMapSize(map) ==
0);
705
706 cxMapFree(map);
707 CX_TEST_ASSERT(cx_testing_allocator_verify(&talloc));
708 }
709 cx_testing_allocator_destroy(&talloc);
710 if (f) fclose(f);
711 remove(fname);
712 }
713
714 CX_TEST(test_properties_multiple_fill) {
715 const char *props1 =
"key1 = value1\n";
716 const char *props2 =
"key2 = value2\n";
717 const char *props3 =
"key3 = value3\n";
718
719 CxProperties prop;
720 cxPropertiesInitDefault(&prop);
721 CxPropertiesStatus result;
722 cxstring key;
723 cxstring value;
724 CX_TEST_DO {
725 cxPropertiesFill(&prop, props1);
726 cxPropertiesFill(&prop, props2);
727 cxPropertiesFill(&prop, props3);
728 result = cxPropertiesNext(&prop, &key, &value);
729 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
730 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"key1")));
731 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"value1")));
732 result = cxPropertiesNext(&prop, &key, &value);
733 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
734 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"key2")));
735 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"value2")));
736 result = cxPropertiesNext(&prop, &key, &value);
737 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
738 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"key3")));
739 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"value3")));
740
741 result = cxPropertiesNext(&prop, &key, &value);
742 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_DATA);
743 }
744 cxPropertiesDestroy(&prop);
745 }
746
747 CX_TEST(test_properties_use_stack) {
748 const char *props1 =
"key1 = val";
749 const char *props2 =
"ue1\nkey2 = value2";
750 const char *props3 =
"\nkey3 = value3\n";
751 char stackmem[
16];
752
753 CxProperties prop;
754 cxPropertiesInitDefault(&prop);
755 cxPropertiesUseStack(&prop, stackmem,
16);
756 CxPropertiesStatus result;
757 cxstring key;
758 cxstring value;
759 CX_TEST_DO {
760 cxPropertiesFill(&prop, props1);
761 result = cxPropertiesNext(&prop, &key, &value);
762 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
763 cxPropertiesFill(&prop, props2);
764 result = cxPropertiesNext(&prop, &key, &value);
765 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
766 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"key1")));
767 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"value1")));
768 result = cxPropertiesNext(&prop, &key, &value);
769 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INCOMPLETE_DATA);
770 cxPropertiesFill(&prop, props3);
771 result = cxPropertiesNext(&prop, &key, &value);
772 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
773 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"key2")));
774 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"value2")));
775 result = cxPropertiesNext(&prop, &key, &value);
776 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
777 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"key3")));
778 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"value3")));
779 result = cxPropertiesNext(&prop, &key, &value);
780 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_DATA);
781 }
782 cxPropertiesDestroy(&prop);
783 }
784
785 CX_TEST(test_properties_empty_key) {
786 const char *fail1 =
"= val\n";
787 const char *fail2 =
" = val\n";
788 const char *good =
" key = val\n";
789
790 CxProperties prop;
791 CxPropertiesStatus result;
792 cxstring key;
793 cxstring value;
794 CX_TEST_DO {
795 cxPropertiesInitDefault(&prop);
796 cxPropertiesFill(&prop, fail1);
797 result = cxPropertiesNext(&prop, &key, &value);
798 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INVALID_EMPTY_KEY);
799 cxPropertiesReset(&prop);
800 cxPropertiesFill(&prop, fail2);
801 result = cxPropertiesNext(&prop, &key, &value);
802 CX_TEST_ASSERT(result ==
CX_PROPERTIES_INVALID_EMPTY_KEY);
803 cxPropertiesReset(&prop);
804 cxPropertiesFill(&prop, good);
805 result = cxPropertiesNext(&prop, &key, &value);
806 CX_TEST_ASSERT(result ==
CX_PROPERTIES_NO_ERROR);
807 CX_TEST_ASSERT(
0 == cx_strcmp(key, cx_str(
"key")));
808 CX_TEST_ASSERT(
0 == cx_strcmp(value, cx_str(
"val")));
809 cxPropertiesDestroy(&prop);
810 }
811 }
812
813 CxTestSuite *cx_test_suite_properties(
void) {
814 CxTestSuite *suite = cx_test_suite_new(
"properties");
815
816 cx_test_register(suite, test_properties_init);
817 cx_test_register(suite, test_properties_next);
818 cx_test_register(suite, test_properties_next_multi);
819 cx_test_register(suite, test_properties_next_part);
820 cx_test_register(suite, test_properties_next_long_lines);
821 cx_test_register(suite, test_properties_next_line_continuation);
822 cx_test_register(suite, test_properties_next_line_continuation_part);
823 cx_test_register(suite, test_properties_load);
824 cx_test_register(suite, test_properties_load_empty_file);
825 cx_test_register(suite, test_properties_load_only_comments);
826 cx_test_register(suite, test_properties_load_error);
827 cx_test_register(suite, test_properties_load_file_not_exists);
828 cx_test_register(suite, test_properties_load_cxmutstr_map);
829 cx_test_register(suite, test_properties_load_incompatible_map);
830 cx_test_register(suite, test_properties_multiple_fill);
831 cx_test_register(suite, test_properties_use_stack);
832 cx_test_register(suite, test_properties_empty_key);
833
834 return suite;
835 }
836