1 #include <stdlib.h>
2 #include <string.h>
3 #include <libxml/parser.h>
4 #include <libxml/dict.h>
5
6
7 /**** dictionary tests ****/
8
9 /* #define WITH_PRINT */
10
11 static const char *seeds1[] = {
12 "a", "b", "c",
13 "d", "e", "f",
14 "g", "h", "i",
15 "j", "k", "l",
16
17 NULL
18 };
19
20 static const char *seeds2[] = {
21 "m", "n", "o",
22 "p", "q", "r",
23 "s", "t", "u",
24 "v", "w", "x",
25
26 NULL
27 };
28
29 #define NB_STRINGS_MAX 100000
30 #define NB_STRINGS_NS 10000
31 #define NB_STRINGS_PREFIX (NB_STRINGS_NS / 20)
32 #define NB_STRINGS_MIN 10
33
34 static xmlChar **strings1;
35 static xmlChar **strings2;
36 static const xmlChar **test1;
37 static const xmlChar **test2;
38 static int nbErrors = 0;
39
40 static void
fill_string_pool(xmlChar ** strings,const char ** seeds)41 fill_string_pool(xmlChar **strings, const char **seeds) {
42 int i, j, k;
43 int start_ns = NB_STRINGS_MAX - NB_STRINGS_NS;
44
45 /*
46 * That's a bit nasty but the output is fine and it doesn't take hours
47 * there is a small but sufficient number of duplicates, and we have
48 * ":xxx" and full QNames in the last NB_STRINGS_NS values
49 */
50 for (i = 0; seeds[i] != NULL; i++) {
51 strings[i] = xmlStrdup((const xmlChar *) seeds[i]);
52 if (strings[i] == NULL) {
53 fprintf(stderr, "Out of memory while generating strings\n");
54 exit(1);
55 }
56 }
57 for (j = 0, k = 0; i < start_ns; i++) {
58 strings[i] = xmlStrncatNew(strings[j], strings[k], -1);
59 if (strings[i] == NULL) {
60 fprintf(stderr, "Out of memory while generating strings\n");
61 exit(1);
62 }
63 if (xmlStrlen(strings[i]) > 30) {
64 fprintf(stderr, "### %s %s\n", strings[start_ns+j], strings[k]);
65 abort();
66 }
67 j++;
68 if (j >= 50) {
69 j = 0;
70 k++;
71 }
72 }
73 for (j = 0, k = 0; (j < NB_STRINGS_PREFIX) && (i < NB_STRINGS_MAX);
74 i++, j++) {
75 strings[i] = xmlStrncatNew(strings[k], (const xmlChar *) ":", -1);
76 if (strings[i] == NULL) {
77 fprintf(stderr, "Out of memory while generating strings\n");
78 exit(1);
79 }
80 k += 1;
81 if (k >= start_ns) k = 0;
82 }
83 for (j = 0, k = 0; i < NB_STRINGS_MAX; i++) {
84 strings[i] = xmlStrncatNew(strings[start_ns+j], strings[k], -1);
85 if (strings[i] == NULL) {
86 fprintf(stderr, "Out of memory while generating strings\n");
87 exit(1);
88 }
89 j++;
90 if (j >= NB_STRINGS_PREFIX) j = 0;
91 k += 5;
92 if (k >= start_ns) k = 0;
93 }
94 }
95
96 #ifdef WITH_PRINT
print_strings(void)97 static void print_strings(void) {
98 int i;
99
100 for (i = 0; i < NB_STRINGS_MAX;i++) {
101 printf("%s\n", strings1[i]);
102 }
103 for (i = 0; i < NB_STRINGS_MAX;i++) {
104 printf("%s\n", strings2[i]);
105 }
106 }
107 #endif
108
clean_strings(void)109 static void clean_strings(void) {
110 int i;
111
112 for (i = 0; i < NB_STRINGS_MAX; i++) {
113 if (strings1[i] != NULL) /* really should not happen */
114 xmlFree(strings1[i]);
115 }
116 for (i = 0; i < NB_STRINGS_MAX; i++) {
117 if (strings2[i] != NULL) /* really should not happen */
118 xmlFree(strings2[i]);
119 }
120 }
121
122 /*
123 * This tests the sub-dictionary support
124 */
125 static int
test_subdict(xmlDictPtr parent)126 test_subdict(xmlDictPtr parent) {
127 int i, j;
128 xmlDictPtr dict;
129 int ret = 0;
130 xmlChar prefix[40];
131 xmlChar *cur, *pref;
132 const xmlChar *tmp;
133
134 dict = xmlDictCreateSub(parent);
135 if (dict == NULL) {
136 fprintf(stderr, "Out of memory while creating sub-dictionary\n");
137 exit(1);
138 }
139 /* Cast to avoid buggy warning on MSVC. */
140 memset((void *) test2, 0, sizeof(test2));
141
142 /*
143 * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow
144 * and we allocate all those doing the fast key computations
145 * All the strings are based on a different seeds subset so we know
146 * they are allocated in the main dictionary, not coming from the parent
147 */
148 for (i = 0;i < NB_STRINGS_MIN;i++) {
149 test2[i] = xmlDictLookup(dict, strings2[i], -1);
150 if (test2[i] == NULL) {
151 fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]);
152 ret = 1;
153 nbErrors++;
154 }
155 }
156 j = NB_STRINGS_MAX - NB_STRINGS_NS;
157 /* ":foo" like strings2 */
158 for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
159 test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j]));
160 if (test2[j] == NULL) {
161 fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]);
162 ret = 1;
163 nbErrors++;
164 }
165 }
166 /* "a:foo" like strings2 */
167 j = NB_STRINGS_MAX - NB_STRINGS_MIN;
168 for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
169 test2[j] = xmlDictLookup(dict, strings2[j], xmlStrlen(strings2[j]));
170 if (test2[j] == NULL) {
171 fprintf(stderr, "Failed lookup for '%s'\n", strings2[j]);
172 ret = 1;
173 nbErrors++;
174 }
175 }
176
177 /*
178 * At this point allocate all the strings
179 * the dictionary will grow in the process, reallocate more string tables
180 * and switch to the better key generator
181 */
182 for (i = 0;i < NB_STRINGS_MAX;i++) {
183 if (test2[i] != NULL)
184 continue;
185 test2[i] = xmlDictLookup(dict, strings2[i], -1);
186 if (test2[i] == NULL) {
187 fprintf(stderr, "Failed lookup for '%s'\n", strings2[i]);
188 ret = 1;
189 nbErrors++;
190 }
191 }
192
193 /*
194 * Now we can start to test things, first that all strings2 belongs to
195 * the dict, and that none of them was actually allocated in the parent
196 */
197 for (i = 0;i < NB_STRINGS_MAX;i++) {
198 if (!xmlDictOwns(dict, test2[i])) {
199 fprintf(stderr, "Failed ownership failure for '%s'\n",
200 strings2[i]);
201 ret = 1;
202 nbErrors++;
203 }
204 if (xmlDictOwns(parent, test2[i])) {
205 fprintf(stderr, "Failed parent ownership failure for '%s'\n",
206 strings2[i]);
207 ret = 1;
208 nbErrors++;
209 }
210 }
211
212 /*
213 * Also verify that all strings from the parent are seen from the subdict
214 */
215 for (i = 0;i < NB_STRINGS_MAX;i++) {
216 if (!xmlDictOwns(dict, test1[i])) {
217 fprintf(stderr, "Failed sub-ownership failure for '%s'\n",
218 strings1[i]);
219 ret = 1;
220 nbErrors++;
221 }
222 }
223
224 /*
225 * Then that another lookup to the string in sub will return the same
226 */
227 for (i = 0;i < NB_STRINGS_MAX;i++) {
228 if (xmlDictLookup(dict, strings2[i], -1) != test2[i]) {
229 fprintf(stderr, "Failed re-lookup check for %d, '%s'\n",
230 i, strings2[i]);
231 ret = 1;
232 nbErrors++;
233 }
234 }
235 /*
236 * But also that any lookup for a string in the parent will be provided
237 * as in the parent
238 */
239 for (i = 0;i < NB_STRINGS_MAX;i++) {
240 if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) {
241 fprintf(stderr, "Failed parent string lookup check for %d, '%s'\n",
242 i, strings1[i]);
243 ret = 1;
244 nbErrors++;
245 }
246 }
247
248 /*
249 * check the QName lookups
250 */
251 for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) {
252 cur = strings2[i];
253 pref = &prefix[0];
254 while (*cur != ':') *pref++ = *cur++;
255 cur++;
256 *pref = 0;
257 tmp = xmlDictQLookup(dict, &prefix[0], cur);
258 if (tmp != test2[i]) {
259 fprintf(stderr, "Failed lookup check for '%s':'%s'\n",
260 &prefix[0], cur);
261 ret = 1;
262 nbErrors++;
263 }
264 }
265 /*
266 * check the QName lookups for strings from the parent
267 */
268 for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) {
269 cur = strings1[i];
270 pref = &prefix[0];
271 while (*cur != ':') *pref++ = *cur++;
272 cur++;
273 *pref = 0;
274 tmp = xmlDictQLookup(dict, &prefix[0], cur);
275 if (xmlDictQLookup(dict, &prefix[0], cur) != test1[i]) {
276 fprintf(stderr, "Failed parent lookup check for '%s':'%s'\n",
277 &prefix[0], cur);
278 ret = 1;
279 nbErrors++;
280 }
281 }
282
283 xmlDictFree(dict);
284 return(ret);
285 }
286
287 /*
288 * Test a single dictionary
289 */
290 static int
test_dict(xmlDict * dict)291 test_dict(xmlDict *dict) {
292 int i, j;
293 int ret = 0;
294 xmlChar prefix[40];
295 xmlChar *cur, *pref;
296 const xmlChar *tmp;
297
298 /* Cast to avoid buggy warning on MSVC. */
299 memset((void *) test1, 0, sizeof(test1));
300
301 /*
302 * Fill in NB_STRINGS_MIN, at this point the dictionary should not grow
303 * and we allocate all those doing the fast key computations
304 */
305 for (i = 0;i < NB_STRINGS_MIN;i++) {
306 test1[i] = xmlDictLookup(dict, strings1[i], -1);
307 if (test1[i] == NULL) {
308 fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]);
309 ret = 1;
310 nbErrors++;
311 }
312 }
313 j = NB_STRINGS_MAX - NB_STRINGS_NS;
314 /* ":foo" like strings1 */
315 for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
316 test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j]));
317 if (test1[j] == NULL) {
318 fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]);
319 ret = 1;
320 nbErrors++;
321 }
322 }
323 /* "a:foo" like strings1 */
324 j = NB_STRINGS_MAX - NB_STRINGS_MIN;
325 for (i = 0;i < NB_STRINGS_MIN;i++, j++) {
326 test1[j] = xmlDictLookup(dict, strings1[j], xmlStrlen(strings1[j]));
327 if (test1[j] == NULL) {
328 fprintf(stderr, "Failed lookup for '%s'\n", strings1[j]);
329 ret = 1;
330 nbErrors++;
331 }
332 }
333
334 /*
335 * At this point allocate all the strings
336 * the dictionary will grow in the process, reallocate more string tables
337 * and switch to the better key generator
338 */
339 for (i = 0;i < NB_STRINGS_MAX;i++) {
340 if (test1[i] != NULL)
341 continue;
342 test1[i] = xmlDictLookup(dict, strings1[i], -1);
343 if (test1[i] == NULL) {
344 fprintf(stderr, "Failed lookup for '%s'\n", strings1[i]);
345 ret = 1;
346 nbErrors++;
347 }
348 }
349
350 /*
351 * Now we can start to test things, first that all strings1 belongs to
352 * the dict
353 */
354 for (i = 0;i < NB_STRINGS_MAX;i++) {
355 if (!xmlDictOwns(dict, test1[i])) {
356 fprintf(stderr, "Failed ownership failure for '%s'\n",
357 strings1[i]);
358 ret = 1;
359 nbErrors++;
360 }
361 }
362
363 /*
364 * Then that another lookup to the string will return the same
365 */
366 for (i = 0;i < NB_STRINGS_MAX;i++) {
367 if (xmlDictLookup(dict, strings1[i], -1) != test1[i]) {
368 fprintf(stderr, "Failed re-lookup check for %d, '%s'\n",
369 i, strings1[i]);
370 ret = 1;
371 nbErrors++;
372 }
373 }
374
375 /*
376 * More complex, check the QName lookups
377 */
378 for (i = NB_STRINGS_MAX - NB_STRINGS_NS;i < NB_STRINGS_MAX;i++) {
379 cur = strings1[i];
380 pref = &prefix[0];
381 while (*cur != ':') *pref++ = *cur++;
382 cur++;
383 *pref = 0;
384 tmp = xmlDictQLookup(dict, &prefix[0], cur);
385 if (tmp != test1[i]) {
386 fprintf(stderr, "Failed lookup check for '%s':'%s'\n",
387 &prefix[0], cur);
388 ret = 1;
389 nbErrors++;
390 }
391 }
392
393 return(ret);
394 }
395
396 static int
testall_dict(void)397 testall_dict(void) {
398 xmlDictPtr dict;
399 int ret = 0;
400
401 strings1 = xmlMalloc(NB_STRINGS_MAX * sizeof(strings1[0]));
402 memset(strings1, 0, NB_STRINGS_MAX * sizeof(strings1[0]));
403 strings2 = xmlMalloc(NB_STRINGS_MAX * sizeof(strings2[0]));
404 memset(strings2, 0, NB_STRINGS_MAX * sizeof(strings2[0]));
405 test1 = xmlMalloc(NB_STRINGS_MAX * sizeof(test1[0]));
406 memset(test1, 0, NB_STRINGS_MAX * sizeof(test1[0]));
407 test2 = xmlMalloc(NB_STRINGS_MAX * sizeof(test2[0]));
408 memset(test2, 0, NB_STRINGS_MAX * sizeof(test2[0]));
409
410 fill_string_pool(strings1, seeds1);
411 fill_string_pool(strings2, seeds2);
412 #ifdef WITH_PRINT
413 print_strings();
414 #endif
415
416 dict = xmlDictCreate();
417 if (dict == NULL) {
418 fprintf(stderr, "Out of memory while creating dictionary\n");
419 exit(1);
420 }
421 if (test_dict(dict) != 0) {
422 ret = 1;
423 }
424 if (test_subdict(dict) != 0) {
425 ret = 1;
426 }
427 xmlDictFree(dict);
428
429 clean_strings();
430 xmlFree(strings1);
431 xmlFree(strings2);
432 xmlFree(test1);
433 xmlFree(test2);
434
435 return ret;
436 }
437
438
439 /**** Hash table tests ****/
440
441 static unsigned
442 rng_state[2] = { 123, 456 };
443
444 #define HASH_ROL(x,n) ((x) << (n) | ((x) & 0xFFFFFFFF) >> (32 - (n)))
445
446 #ifdef __clang__
447 __attribute__ ((no_sanitize("unsigned-integer-overflow")))
448 __attribute__ ((no_sanitize("unsigned-shift-base")))
449 #endif
450 static unsigned
my_rand(unsigned max)451 my_rand(unsigned max) {
452 unsigned s0 = rng_state[0];
453 unsigned s1 = rng_state[1];
454 unsigned result = HASH_ROL(s0 * 0x9E3779BB, 5) * 5;
455
456 s1 ^= s0;
457 rng_state[0] = HASH_ROL(s0, 26) ^ s1 ^ (s1 << 9);
458 rng_state[1] = HASH_ROL(s1, 13);
459
460 return((result & 0xFFFFFFFF) % max);
461 }
462
463 static xmlChar *
gen_random_string(xmlChar id)464 gen_random_string(xmlChar id) {
465 unsigned size = my_rand(64) + 1;
466 unsigned id_pos = my_rand(size);
467 size_t j;
468
469 xmlChar *str = xmlMalloc(size + 1);
470 for (j = 0; j < size; j++) {
471 str[j] = 'a' + my_rand(26);
472 }
473 str[id_pos] = id;
474 str[size] = 0;
475
476 /* Generate QName in 75% of cases */
477 if (size > 3 && my_rand(4) > 0) {
478 unsigned colon_pos = my_rand(size - 3) + 1;
479
480 if (colon_pos >= id_pos)
481 colon_pos++;
482 str[colon_pos] = ':';
483 }
484
485 return str;
486 }
487
488 typedef struct {
489 xmlChar **strings;
490 size_t num_entries;
491 size_t num_keys;
492 size_t num_strings;
493 size_t index;
494 xmlChar id;
495 } StringPool;
496
497 static StringPool *
pool_new(size_t num_entries,size_t num_keys,xmlChar id)498 pool_new(size_t num_entries, size_t num_keys, xmlChar id) {
499 StringPool *ret;
500 size_t num_strings;
501
502 ret = xmlMalloc(sizeof(*ret));
503 ret->num_entries = num_entries;
504 ret->num_keys = num_keys;
505 num_strings = num_entries * num_keys;
506 ret->strings = xmlMalloc(num_strings * sizeof(ret->strings[0]));
507 memset(ret->strings, 0, num_strings * sizeof(ret->strings[0]));
508 ret->num_strings = num_strings;
509 ret->index = 0;
510 ret->id = id;
511
512 return ret;
513 }
514
515 static void
pool_free(StringPool * pool)516 pool_free(StringPool *pool) {
517 size_t i;
518
519 for (i = 0; i < pool->num_strings; i++) {
520 xmlFree(pool->strings[i]);
521 }
522 xmlFree(pool->strings);
523 xmlFree(pool);
524 }
525
526 static int
pool_done(StringPool * pool)527 pool_done(StringPool *pool) {
528 return pool->index >= pool->num_strings;
529 }
530
531 static void
pool_reset(StringPool * pool)532 pool_reset(StringPool *pool) {
533 pool->index = 0;
534 }
535
536 static int
pool_bulk_insert(StringPool * pool,xmlHashTablePtr hash,size_t num)537 pool_bulk_insert(StringPool *pool, xmlHashTablePtr hash, size_t num) {
538 size_t i, j;
539 int ret = 0;
540
541 for (i = pool->index, j = 0; i < pool->num_strings && j < num; j++) {
542 xmlChar *str[3];
543 size_t k;
544
545 while (1) {
546 xmlChar tmp_key[1];
547 int res;
548
549 for (k = 0; k < pool->num_keys; k++)
550 str[k] = gen_random_string(pool->id);
551
552 switch (pool->num_keys) {
553 case 1:
554 res = xmlHashAddEntry(hash, str[0], tmp_key);
555 if (res == 0 &&
556 xmlHashUpdateEntry(hash, str[0], str[0], NULL) != 0)
557 ret = -1;
558 break;
559 case 2:
560 res = xmlHashAddEntry2(hash, str[0], str[1], tmp_key);
561 if (res == 0 &&
562 xmlHashUpdateEntry2(hash, str[0], str[1], str[0],
563 NULL) != 0)
564 ret = -1;
565 break;
566 case 3:
567 res = xmlHashAddEntry3(hash, str[0], str[1], str[2],
568 tmp_key);
569 if (res == 0 &&
570 xmlHashUpdateEntry3(hash, str[0], str[1], str[2],
571 str[0], NULL) != 0)
572 ret = -1;
573 break;
574 }
575
576 if (res == 0)
577 break;
578 for (k = 0; k < pool->num_keys; k++)
579 xmlFree(str[k]);
580 }
581
582 for (k = 0; k < pool->num_keys; k++)
583 pool->strings[i++] = str[k];
584 }
585
586 pool->index = i;
587 return ret;
588 }
589
590 static xmlChar *
hash_qlookup(xmlHashTable * hash,xmlChar ** names,size_t num_keys)591 hash_qlookup(xmlHashTable *hash, xmlChar **names, size_t num_keys) {
592 xmlChar *prefix[3];
593 const xmlChar *local[3];
594 xmlChar *res;
595 size_t i;
596
597 for (i = 0; i < 3; ++i) {
598 if (i >= num_keys) {
599 prefix[i] = NULL;
600 local[i] = NULL;
601 } else {
602 const xmlChar *name = names[i];
603 const xmlChar *colon = BAD_CAST strchr((const char *) name, ':');
604
605 if (colon == NULL) {
606 prefix[i] = NULL;
607 local[i] = name;
608 } else {
609 prefix[i] = xmlStrndup(name, colon - name);
610 local[i] = &colon[1];
611 }
612 }
613 }
614
615 res = xmlHashQLookup3(hash, prefix[0], local[0], prefix[1], local[1],
616 prefix[2], local[2]);
617
618 for (i = 0; i < 3; ++i)
619 xmlFree(prefix[i]);
620
621 return res;
622 }
623
624 static int
pool_bulk_lookup(StringPool * pool,xmlHashTablePtr hash,size_t num,int existing)625 pool_bulk_lookup(StringPool *pool, xmlHashTablePtr hash, size_t num,
626 int existing) {
627 size_t i, j;
628 int ret = 0;
629
630 for (i = pool->index, j = 0; i < pool->num_strings && j < num; j++) {
631 xmlChar **str = &pool->strings[i];
632 int q;
633
634 for (q = 0; q < 2; q++) {
635 xmlChar *res = NULL;
636
637 if (q) {
638 res = hash_qlookup(hash, str, pool->num_keys);
639 } else {
640 switch (pool->num_keys) {
641 case 1:
642 res = xmlHashLookup(hash, str[0]);
643 break;
644 case 2:
645 res = xmlHashLookup2(hash, str[0], str[1]);
646 break;
647 case 3:
648 res = xmlHashLookup3(hash, str[0], str[1], str[2]);
649 break;
650 }
651 }
652
653 if (existing) {
654 if (res != str[0])
655 ret = -1;
656 } else {
657 if (res != NULL)
658 ret = -1;
659 }
660 }
661
662 i += pool->num_keys;
663 }
664
665 pool->index = i;
666 return ret;
667 }
668
669 static int
pool_bulk_remove(StringPool * pool,xmlHashTablePtr hash,size_t num)670 pool_bulk_remove(StringPool *pool, xmlHashTablePtr hash, size_t num) {
671 size_t i, j;
672 int ret = 0;
673
674 for (i = pool->index, j = 0; i < pool->num_strings && j < num; j++) {
675 xmlChar **str = &pool->strings[i];
676 int res = -1;
677
678 switch (pool->num_keys) {
679 case 1:
680 res = xmlHashRemoveEntry(hash, str[0], NULL);
681 break;
682 case 2:
683 res = xmlHashRemoveEntry2(hash, str[0], str[1], NULL);
684 break;
685 case 3:
686 res = xmlHashRemoveEntry3(hash, str[0], str[1], str[2], NULL);
687 break;
688 }
689
690 if (res != 0)
691 ret = -1;
692
693 i += pool->num_keys;
694 }
695
696 pool->index = i;
697 return ret;
698 }
699
700 static int
test_hash(size_t num_entries,size_t num_keys,int use_dict)701 test_hash(size_t num_entries, size_t num_keys, int use_dict) {
702 xmlDict *dict = NULL;
703 xmlHashTable *hash;
704 StringPool *pool1, *pool2;
705 int ret = 0;
706
707 if (use_dict) {
708 dict = xmlDictCreate();
709 hash = xmlHashCreateDict(0, dict);
710 } else {
711 hash = xmlHashCreate(0);
712 }
713 pool1 = pool_new(num_entries, num_keys, '1');
714 pool2 = pool_new(num_entries, num_keys, '2');
715
716 /* Insert all strings from pool2 and about half of pool1. */
717 while (!pool_done(pool2)) {
718 if (pool_bulk_insert(pool1, hash, my_rand(50)) != 0) {
719 fprintf(stderr, "pool1: hash insert failed\n");
720 ret = 1;
721 }
722 if (pool_bulk_insert(pool2, hash, my_rand(100)) != 0) {
723 fprintf(stderr, "pool1: hash insert failed\n");
724 ret = 1;
725 }
726 }
727
728 /* Check existing entries */
729 pool_reset(pool2);
730 if (pool_bulk_lookup(pool2, hash, pool2->num_entries, 1) != 0) {
731 fprintf(stderr, "pool2: hash lookup failed\n");
732 ret = 1;
733 }
734
735 /* Remove all strings from pool2 and insert the rest of pool1. */
736 pool_reset(pool2);
737 while (!pool_done(pool1) || !pool_done(pool2)) {
738 if (pool_bulk_insert(pool1, hash, my_rand(50)) != 0) {
739 fprintf(stderr, "pool1: hash insert failed\n");
740 ret = 1;
741 }
742 if (pool_bulk_remove(pool2, hash, my_rand(100)) != 0) {
743 fprintf(stderr, "pool2: hash remove failed\n");
744 ret = 1;
745 }
746 }
747
748 /* Check existing entries */
749 pool_reset(pool1);
750 if (pool_bulk_lookup(pool1, hash, pool1->num_entries, 1) != 0) {
751 fprintf(stderr, "pool1: hash lookup failed\n");
752 ret = 1;
753 }
754
755 /* Check removed entries */
756 pool_reset(pool2);
757 if (pool_bulk_lookup(pool2, hash, pool2->num_entries, 0) != 0) {
758 fprintf(stderr, "pool2: hash lookup succeeded unexpectedly\n");
759 ret = 1;
760 }
761
762 pool_free(pool1);
763 pool_free(pool2);
764 xmlHashFree(hash, NULL);
765 xmlDictFree(dict);
766
767 return ret;
768 }
769
770 static int
testall_hash(void)771 testall_hash(void) {
772 size_t num_keys;
773
774 for (num_keys = 1; num_keys <= 3; num_keys++) {
775 size_t num_strings;
776 size_t max_strings = num_keys == 1 ? 100000 : 1000;
777
778 for (num_strings = 10; num_strings <= max_strings; num_strings *= 10) {
779 size_t reps, i;
780
781 reps = 1000 / num_strings;
782 if (reps == 0)
783 reps = 1;
784
785 for (i = 0; i < reps; i++) {
786 if (test_hash(num_strings, num_keys, /* use_dict */ 0) != 0)
787 return(1);
788 }
789
790 if (test_hash(num_strings, num_keys, /* use_dict */ 1) != 0)
791 return(1);
792 }
793 }
794
795 return(0);
796 }
797
798
799 /**** main ****/
800
801 int
main(void)802 main(void) {
803 int ret = 0;
804
805 LIBXML_TEST_VERSION
806
807 if (testall_dict() != 0) {
808 fprintf(stderr, "dictionary tests failed\n");
809 ret = 1;
810 }
811 if (testall_hash() != 0) {
812 fprintf(stderr, "hash tests failed\n");
813 ret = 1;
814 }
815
816 xmlCleanupParser();
817 return(ret);
818 }
819