1 /*
2 * Copyright (c) 2011 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Angus Salkeld <asalkeld@redhat.com>
7 *
8 * This file is part of libqb.
9 *
10 * libqb is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation, either version 2.1 of the License, or
13 * (at your option) any later version.
14 *
15 * libqb is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with libqb. If not, see <http://www.gnu.org/licenses/>.
22 */
23 #include "os_base.h"
24
25 #include "check_common.h"
26
27 #include <qb/qbdefs.h>
28 #include <qb/qblog.h>
29 #include <qb/qbmap.h>
30
31 const char *chars[] = {
32 "0","1","2","3","4","5","6","7","8","9",
33 "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z",
34 "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
35 NULL,
36 };
37
38 const char *chars2[] = {
39 "0","1","2","3","4","5","6","7","8","9",
40 "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
41 NULL,
42 };
43
44 const char *composers[] = {
45 "Béla Bartók",
46 "Zoltán Kodály",
47 "Ludwig van Beethoven",
48 "Wolfgang Amadeus Mozart",
49 "Leoš Janáček",
50 "Benjamin Britten",
51 "Josef Haydn",
52 "Claude Debussy",
53 "Charles Ives",
54 /* Maybe in an alien language ... but they can cause trie crashes & conflicts */
55 "\x7e\x7f\x80\x81", "\x7e", "\x7e\x7f", "\x7e\x7f\x80",
56 };
57
58
59 static char *notified_key = NULL;
60 static void *notified_value = NULL;
61 static void *notified_new_value = NULL;
62 static void *notified_user_data = NULL;
63 static int32_t notified_event = 0;
64 static int32_t notified_event_prev = 0;
65 static int32_t notified_events = 0;
66
67 static void
68 my_map_notification_iter(uint32_t event,
69 char* key, void* old_value,
70 void* value, void* user_data)
71 {
72 const char *p;
73 void *data;
74 qb_map_t *m = (qb_map_t *)user_data;
75 qb_map_iter_t *it = qb_map_iter_create(m);
76
77 notified_events++;
78
79 for (p = qb_map_iter_next(it, &data); p; p = qb_map_iter_next(it, &data)) {
80 printf("%s > %s\n", p, (char*) data);
81 }
82 qb_map_iter_free(it);
83 }
84
85 /*
86 * create some entries
87 * add a notifier
88 * delete an entry
89 * in the notifier iterate over the map.
90 */
91 static void
92 test_map_notifications_iter(qb_map_t *m)
93 {
94 int i;
95
96 qb_map_put(m, "k1", "one");
97 qb_map_put(m, "k12", "two");
98 qb_map_put(m, "k34", "three");
99 ck_assert_int_eq(qb_map_count_get(m), 3);
100
101 notified_events = 0;
102 i = qb_map_notify_add(m, NULL, my_map_notification_iter,
103 (QB_MAP_NOTIFY_DELETED |
104 QB_MAP_NOTIFY_RECURSIVE), m);
105 ck_assert_int_eq(i, 0);
106 qb_map_rm(m, "k12");
107 ck_assert_int_eq(notified_events, 1);
108 ck_assert_int_eq(qb_map_count_get(m), 2);
109 }
110
111 static void
112 test_map_simple(qb_map_t *m, const char *name)
113 {
114 int i;
115 const char *p;
116 void *data;
117 qb_map_iter_t *it;
118
119 qb_map_put(m, "k1", "one");
120 qb_map_put(m, "k12", "two");
121 qb_map_put(m, "k34", "three");
122 ck_assert_int_eq(qb_map_count_get(m), 3);
123 qb_map_put(m, "k3", "four");
124 ck_assert_int_eq(qb_map_count_get(m), 4);
125
126 it = qb_map_iter_create(m);
127 i = 0;
128 for (p = qb_map_iter_next(it, &data); p; p = qb_map_iter_next(it, &data)) {
129 printf("%25s(%d) %s > %s\n", name, i, p, (char*) data);
130 i++;
131 }
132 qb_map_iter_free(it);
133 ck_assert_int_eq(i, 4);
134
135 ck_assert_str_eq(qb_map_get(m, "k34"), "three");
136 ck_assert_str_eq(qb_map_get(m, "k1"), "one");
137 ck_assert_str_eq(qb_map_get(m, "k12"), "two");
138 ck_assert_str_eq(qb_map_get(m, "k3"), "four");
139
140 qb_map_rm(m, "k12");
141 ck_assert_int_eq(qb_map_count_get(m), 3);
142 qb_map_put(m, "9k", "nine");
143
144 qb_map_put(m, "k34", "not_three");
145 ck_assert_str_eq(qb_map_get(m, "k34"), "not_three");
146 ck_assert_int_eq(qb_map_count_get(m), 4);
147
148 qb_map_destroy(m);
149 }
150
151 static int32_t
152 my_traverse(const char *key, void *value, void *data)
153 {
154 ck_assert((*key) > 0);
155 return QB_FALSE;
156 }
157
158 static int32_t
159 check_order(const char *key, void *value, void *data)
160 {
161 int *o = (int*)data;
162 ck_assert_str_eq(chars[*o], key);
163 ck_assert_str_eq(chars[*o], value);
164 (*o)++;
165 return QB_FALSE;
166 }
167
168 static int32_t
169 check_order2(const char *key, void *value, void *data)
170 {
171 int *o = (int*)data;
172 ck_assert_str_eq(chars2[*o], key);
173 ck_assert_str_eq(chars2[*o], value);
174 (*o)++;
175 return QB_FALSE;
176 }
177
178 static void
179 test_map_search(qb_map_t* m)
180 {
181 int32_t i;
182 int32_t removed;
183 int order;
184 char c[2];
185 const char *p;
186
187 for (i = 0; chars[i]; i++) {
188 qb_map_put(m, chars[i], chars[i]);
189 }
190 qb_map_foreach(m, my_traverse, NULL);
191
192 ck_assert_int_eq(qb_map_count_get(m), (26*2 + 10));
193
194 order = 0;
195 qb_map_foreach(m, check_order, &order);
196
197 for (i = 0; i < 26; i++) {
198 removed = qb_map_rm(m, chars[i + 10]);
199 ck_assert(removed);
200 }
201
202 c[0] = '\0';
203 c[1] = '\0';
204 removed = qb_map_rm(m, c);
205 ck_assert(!removed);
206
207 qb_map_foreach(m, my_traverse, NULL);
208
209 ck_assert_int_eq(qb_map_count_get(m), 26+10);
210
211 order = 0;
212 qb_map_foreach(m, check_order2, &order);
213
214 for (i = 25; i >= 0; i--) {
215 qb_map_put(m, chars[i + 10], chars[i + 10]);
216 }
217 order = 0;
218 qb_map_foreach(m, check_order, &order);
219
220 c[0] = '0';
221 p = qb_map_get(m, c);
222 ck_assert(p && *p == *c);
223
224 c[0] = 'A';
225 p = qb_map_get(m, c);
226 ck_assert(p && *p == *c);
227
228 c[0] = 'a';
229 p = qb_map_get(m, c);
230 ck_assert(p && *p == *c);
231
232 c[0] = 'z';
233 p = qb_map_get(m, c);
234 ck_assert(p && *p == *c);
235
236 c[0] = '!';
237 p = qb_map_get(m, c);
238 ck_assert(p == NULL);
239
240 c[0] = '=';
241 p = qb_map_get(m, c);
242 ck_assert(p == NULL);
243
244 c[0] = '|';
245 p = qb_map_get(m, c);
246 ck_assert(p == NULL);
247
248 qb_map_destroy(m);
249 }
250
251 static void
252 my_map_notification(uint32_t event,
253 char* key, void* old_value,
254 void* value, void* user_data)
255 {
256 notified_key = key;
257 notified_value = old_value;
258 notified_new_value = value;
259 notified_user_data = user_data;
260 notified_event_prev = notified_event;
261 notified_event = event;
262 }
263
264 static void
265 my_map_notification_2(uint32_t event,
266 char* key, void* old_value,
267 void* value, void* user_data)
268 {
269 }
270
271 static void
272 test_map_remove(qb_map_t *m)
273 {
274 const char * a, *b, *c, *d;
275 int32_t i;
276 int32_t removed;
277 const char *remove_ch[] = {"o","m","k","j","i","g","f","e","d","b","a", NULL};
278
279 i = qb_map_notify_add(m, NULL, my_map_notification,
280 (QB_MAP_NOTIFY_DELETED|
281 QB_MAP_NOTIFY_REPLACED|
282 QB_MAP_NOTIFY_RECURSIVE),
283 m);
284 ck_assert_int_eq(i, 0);
285
286 for (i = 0; chars[i]; i++) {
287 qb_map_put(m, chars[i], chars[i]);
288 }
289
290 a = "0";
291 qb_map_put(m, a, a);
292 ck_assert(notified_key == chars[0]);
293 ck_assert(notified_value == chars[0]);
294 ck_assert(notified_user_data == m);
295 notified_key = NULL;
296 notified_value = NULL;
297 notified_user_data = NULL;
298
299 b = "5";
300 removed = qb_map_rm(m, b);
301 ck_assert(removed);
302 ck_assert(notified_key == chars[5]);
303 ck_assert(notified_value == chars[5]);
304 ck_assert(notified_user_data == m);
305 notified_key = NULL;
306 notified_value = NULL;
307 notified_user_data = NULL;
308
309 d = "1";
310 qb_map_put(m, d, d);
311 ck_assert(notified_key == chars[1]);
312 ck_assert(notified_value == chars[1]);
313 ck_assert(notified_user_data == m);
314 notified_key = NULL;
315 notified_value = NULL;
316
317 c = "2";
318 removed = qb_map_rm(m, c);
319 ck_assert(removed);
320 ck_assert(notified_key == chars[2]);
321 ck_assert(notified_value == chars[2]);
322 notified_key = NULL;
323 notified_value = NULL;
324
325 for (i = 0; remove_ch[i]; i++) {
326 removed = qb_map_rm(m, remove_ch[i]);
327 ck_assert(removed);
328 }
329
330 qb_map_destroy(m);
331 }
332
333 static void
334 test_map_notifications_basic(qb_map_t *m)
335 {
336 int32_t i;
337
338 /* with global notifier */
339 i = qb_map_notify_add(m, NULL, my_map_notification,
340 (QB_MAP_NOTIFY_INSERTED|
341 QB_MAP_NOTIFY_DELETED|
342 QB_MAP_NOTIFY_REPLACED|
343 QB_MAP_NOTIFY_RECURSIVE),
344 m);
345 ck_assert_int_eq(i, 0);
346
347 notified_key = NULL;
348 notified_value = NULL;
349 notified_new_value = NULL;
350
351 /* insert */
352 qb_map_put(m, "garden", "grow");
353 ck_assert_str_eq(notified_key, "garden");
354 ck_assert_str_eq(notified_new_value, "grow");
355 ck_assert(notified_user_data == m);
356
357 /* update */
358 qb_map_put(m, "garden", "green");
359 ck_assert_str_eq(notified_key, "garden");
360 ck_assert_str_eq(notified_value, "grow");
361 ck_assert_str_eq(notified_new_value, "green");
362 ck_assert(notified_user_data == m);
363
364 /* delete */
365 qb_map_rm(m, "garden");
366 ck_assert_str_eq(notified_key, "garden");
367 ck_assert_str_eq(notified_value, "green");
368 ck_assert(notified_user_data == m);
369
370 /* no event with notifier removed */
371 i = qb_map_notify_del(m, NULL, my_map_notification,
372 (QB_MAP_NOTIFY_INSERTED|
373 QB_MAP_NOTIFY_DELETED|
374 QB_MAP_NOTIFY_REPLACED|
375 QB_MAP_NOTIFY_RECURSIVE));
376 ck_assert_int_eq(i, 0);
377 notified_key = NULL;
378 notified_value = NULL;
379 notified_new_value = NULL;
380 qb_map_put(m, "age", "67");
381 ck_assert(notified_key == NULL);
382 ck_assert(notified_value == NULL);
383 ck_assert(notified_new_value == NULL);
384
385 /* deleting a non-existing notification */
386 i = qb_map_notify_del(m, "a", my_map_notification,
387 (QB_MAP_NOTIFY_INSERTED|
388 QB_MAP_NOTIFY_DELETED|
389 QB_MAP_NOTIFY_REPLACED|
390 QB_MAP_NOTIFY_RECURSIVE));
391 ck_assert_int_eq(i, -ENOENT);
392
393 /* test uniquess */
394 qb_map_put(m, "fred", "null");
395 i = qb_map_notify_add(m, "fred", my_map_notification,
396 QB_MAP_NOTIFY_REPLACED, m);
397 ck_assert_int_eq(i, 0);
398 i = qb_map_notify_add(m, "fred", my_map_notification,
399 QB_MAP_NOTIFY_REPLACED, m);
400 ck_assert_int_eq(i, -EEXIST);
401 }
402
403 /* test free'ing notifier
404 *
405 * input:
406 * only one can be added
407 * can only be added with NULL key (global)
408 * output:
409 * is the last notifier called (after deleted or replaced)
410 * recursive is implicit
411 */
412 static void
413 test_map_notifications_free(qb_map_t *m)
414 {
415 int32_t i;
416 i = qb_map_notify_add(m, "not global", my_map_notification,
417 QB_MAP_NOTIFY_FREE, m);
418 ck_assert_int_eq(i, -EINVAL);
419 i = qb_map_notify_add(m, NULL, my_map_notification,
420 QB_MAP_NOTIFY_FREE, m);
421 ck_assert_int_eq(i, 0);
422 i = qb_map_notify_add(m, NULL, my_map_notification_2,
423 QB_MAP_NOTIFY_FREE, m);
424 ck_assert_int_eq(i, -EEXIST);
425 i = qb_map_notify_del_2(m, NULL, my_map_notification,
426 QB_MAP_NOTIFY_FREE, m);
427 ck_assert_int_eq(i, 0);
428 i = qb_map_notify_add(m, NULL, my_map_notification,
429 (QB_MAP_NOTIFY_FREE |
430 QB_MAP_NOTIFY_REPLACED |
431 QB_MAP_NOTIFY_DELETED |
432 QB_MAP_NOTIFY_RECURSIVE), m);
433 ck_assert_int_eq(i, 0);
434
435 qb_map_put(m, "garden", "grow");
436
437 /* update */
438 qb_map_put(m, "garden", "green");
439 ck_assert_int_eq(notified_event_prev, QB_MAP_NOTIFY_REPLACED);
440 ck_assert_int_eq(notified_event, QB_MAP_NOTIFY_FREE);
441
442 /* delete */
443 qb_map_rm(m, "garden");
444 ck_assert_int_eq(notified_event_prev, QB_MAP_NOTIFY_DELETED);
445 ck_assert_int_eq(notified_event, QB_MAP_NOTIFY_FREE);
446 }
447
448 static void
449 test_map_notifications_prefix(qb_map_t *m)
450 {
451 int32_t i;
452
453
454 /* with prefix notifier */
455 i = qb_map_notify_add(m, "add", my_map_notification,
456 (QB_MAP_NOTIFY_INSERTED|
457 QB_MAP_NOTIFY_DELETED|
458 QB_MAP_NOTIFY_REPLACED|
459 QB_MAP_NOTIFY_RECURSIVE),
460 &i);
461 ck_assert_int_eq(i, 0);
462
463 /* insert */
464 qb_map_put(m, "adder", "snake");
465 ck_assert_str_eq(notified_key, "adder");
466 ck_assert_str_eq(notified_new_value, "snake");
467 ck_assert(notified_user_data == &i);
468
469 /* insert (no match) */
470 notified_key = NULL;
471 notified_value = NULL;
472 notified_new_value = NULL;
473 qb_map_put(m, "adjust", "it");
474 ck_assert(notified_key == NULL);
475 ck_assert(notified_value == NULL);
476 ck_assert(notified_new_value == NULL);
477
478 /* update */
479 qb_map_put(m, "adder", "+++");
480 ck_assert_str_eq(notified_key, "adder");
481 ck_assert_str_eq(notified_value, "snake");
482 ck_assert_str_eq(notified_new_value, "+++");
483
484 /* delete */
485 qb_map_rm(m, "adder");
486 ck_assert_str_eq(notified_key, "adder");
487 ck_assert_str_eq(notified_value, "+++");
488
489 }
490
491 static void
492 test_map_traverse_ordered(qb_map_t *m)
493 {
494 int32_t i;
495 const char *p;
496 char *result;
497 void *data;
498 qb_map_iter_t *it = qb_map_iter_create(m);
499
500 for (i = 0; chars[i]; i++) {
501 qb_map_put(m, chars[i], chars[i]);
502 }
503 result = calloc(sizeof(char), 26 * 2 + 10 + 1);
504
505 i = 0;
506 for (p = qb_map_iter_next(it, &data); p; p = qb_map_iter_next(it, &data)) {
507 result[i] = *(char*) data;
508 i++;
509 }
510 qb_map_iter_free(it);
511 ck_assert_str_eq(result,
512 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
513
514 qb_map_destroy(m);
515 }
516
517 static int32_t
518 traverse_and_remove_func(const char *key, void *value, void *data)
519 {
520 int kk = random() % 30;
521 qb_map_t *m = (qb_map_t *)data;
522 qb_map_rm(m, chars[kk]);
523 qb_map_put(m, chars[kk+30], key);
524 return QB_FALSE;
525 }
526
527 static void
528 test_map_iter_safety(qb_map_t *m, int32_t ordered)
529 {
530 void *data;
531 void *data2;
532 const char *p;
533 const char *p2;
534 qb_map_iter_t *it;
535 qb_map_iter_t *it2;
536 int32_t found_good = QB_FALSE;
537
538 qb_map_put(m, "aaaa", "aye");
539 qb_map_put(m, "bbbb", "bee");
540 qb_map_put(m, "cccc", "sea");
541
542 it = qb_map_iter_create(m);
543 it2 = qb_map_iter_create(m);
544 while ((p = qb_map_iter_next(it, &data)) != NULL) {
545 printf("1: %s == %s\n", p, (char*)data);
546 if (strcmp(p, "bbbb") == 0) {
547 qb_map_rm(m, "bbbb");
548 qb_map_rm(m, "cccc");
549 qb_map_rm(m, "aaaa");
550 qb_map_put(m, "fffff", "yum");
551 while ((p2 = qb_map_iter_next(it2, &data2)) != NULL) {
552 printf("2: %s == %s\n", p2, (char*)data2);
553 if (strcmp(p2, "fffff") == 0) {
554 qb_map_put(m, "ggggg", "good");
555 }
556 }
557 qb_map_iter_free(it2);
558 }
559 if (strcmp(p, "ggggg") == 0) {
560 found_good = QB_TRUE;
561 }
562 }
563 qb_map_iter_free(it);
564
565 if (ordered) {
566 ck_assert_int_eq(found_good, QB_TRUE);
567 }
568
569 qb_map_destroy(m);
570 }
571
572 static void
573 test_map_iter_prefix(qb_map_t *m)
574 {
575 void *data;
576 const char *p;
577 qb_map_iter_t *it;
578 int count;
579
580 qb_map_put(m, "aaaa", "aye");
581 qb_map_put(m, "facc", "nope");
582 qb_map_put(m, "abbb", "bee");
583 qb_map_put(m, "a.ac", "nope");
584 qb_map_put(m, "aacc", "yip");
585 qb_map_put(m, "cacc", "nope");
586 qb_map_put(m, "c", "----");
587
588 count = 0;
589 it = qb_map_pref_iter_create(m, "aa");
590 while ((p = qb_map_iter_next(it, &data)) != NULL) {
591 printf("1: %s == %s\n", p, (char*)data);
592 count++;
593 }
594 qb_map_iter_free(it);
595 ck_assert_int_eq(count, 2);
596
597 count = 0;
598 it = qb_map_pref_iter_create(m, "a");
599 while ((p = qb_map_iter_next(it, &data)) != NULL) {
600 printf("2: %s == %s\n", p, (char*)data);
601 count++;
602 }
603 qb_map_iter_free(it);
604 ck_assert_int_eq(count, 4);
605
606 count = 0;
607 it = qb_map_pref_iter_create(m, "zz");
608 while ((p = qb_map_iter_next(it, &data)) != NULL) {
609 printf("??: %s == %s\n", p, (char*)data);
610 count++;
611 }
612 qb_map_iter_free(it);
613 ck_assert_int_eq(count, 0);
614
615 count = 0;
616 it = qb_map_pref_iter_create(m, "c");
617 while ((p = qb_map_iter_next(it, &data)) != NULL) {
618 printf("3: %s == %s\n", p, (char*)data);
619 count++;
620 }
621 qb_map_iter_free(it);
622 ck_assert_int_eq(count, 2);
623
624 qb_map_destroy(m);
625 }
626
627
628 static void
629 test_map_traverse_unordered(qb_map_t *m)
630 {
631 int32_t i;
632 srand(time(NULL));
633 for (i = 0; i < 30; i++) {
634 qb_map_put(m, chars[i], chars[i]);
635 }
636 qb_map_foreach(m, traverse_and_remove_func, m);
637 qb_map_destroy(m);
638 }
639
640 static int32_t
641 my_counter_traverse(const char *key, void *value, void *data)
642 {
643 int32_t *c = (int32_t*)data;
644 (*c)++;
645 return QB_FALSE;
646 }
647
648 static void
649 test_map_load(qb_map_t *m, const char* test_name)
650 {
651 char word[1000];
652 char *w;
653 FILE *fp;
654 int32_t res = 0;
655 int32_t count;
656 int32_t count2;
657 float ops;
658 float secs;
659 void *value;
660 qb_util_stopwatch_t *sw;
661
|
(1) Event cond_true: |
Condition "m != NULL", taking true branch. |
662 ck_assert(m != NULL);
663 sw = qb_util_stopwatch_create();
664
665 #define MAX_WORDS 100000
666
667 /*
668 * Load with dictionary
669 */
670 fp = fopen("/usr/share/dict/words", "r");
671 qb_util_stopwatch_start(sw);
672 count = 0;
|
(2) Event cond_true: |
Condition "fgets(word, 1000 /* sizeof (word) */, fp)", taking true branch. |
|
(3) Event cond_true: |
Condition "count < 100000", taking true branch. |
|
(5) Event loop_begin: |
Jumped back to beginning of loop. |
|
(6) Event cond_true: |
Condition "fgets(word, 1000 /* sizeof (word) */, fp)", taking true branch. |
|
(7) Event cond_true: |
Condition "count < 100000", taking true branch. |
|
(9) Event loop_begin: |
Jumped back to beginning of loop. |
|
(10) Event cond_true: |
Condition "fgets(word, 1000 /* sizeof (word) */, fp)", taking true branch. |
|
(11) Event cond_false: |
Condition "count < 100000", taking false branch. |
673 while (fgets(word, sizeof(word), fp) && count < MAX_WORDS) {
674 w = strdup(word);
675 qb_map_put(m, w, w);
676 count++;
|
(4) Event loop: |
Jumping back to the beginning of the loop. |
|
(8) Event loop: |
Jumping back to the beginning of the loop. |
|
(12) Event loop_end: |
Reached end of loop. |
677 }
678 qb_util_stopwatch_stop(sw);
|
(13) Event cond_true: |
Condition "_ck_x == _ck_y", taking true branch. |
679 ck_assert_int_eq(qb_map_count_get(m), count);
680 fclose(fp);
681 secs = qb_util_stopwatch_sec_elapsed_get(sw);
682 ops = (float)count / secs;
683 qb_log(LOG_INFO, "%25s %12.2f puts/sec (%d/%fs)\n", test_name, ops, count, secs);
684
685 /*
686 * Verify dictionary produces correct values
687 */
688 fp = fopen("/usr/share/dict/words", "r");
689 qb_util_stopwatch_start(sw);
690 count2 = 0;
|
(14) Event cond_true: |
Condition "fgets(word, 1000 /* sizeof (word) */, fp)", taking true branch. |
|
(15) Event cond_true: |
Condition "count2 < 100000", taking true branch. |
|
(28) Event loop_begin: |
Jumped back to beginning of loop. |
|
(29) Event cond_true: |
Condition "fgets(word, 1000 /* sizeof (word) */, fp)", taking true branch. |
|
(30) Event cond_true: |
Condition "count2 < 100000", taking true branch. |
|
(43) Event loop_begin: |
Jumped back to beginning of loop. |
|
(44) Event cond_true: |
Condition "fgets(word, 1000 /* sizeof (word) */, fp)", taking true branch. |
|
(45) Event cond_false: |
Condition "count2 < 100000", taking false branch. |
691 while (fgets(word, sizeof(word), fp) && count2 < MAX_WORDS) {
692 value = qb_map_get(m, word);
|
(16) Event cond_true: |
Condition "_ck_x != NULL", taking true branch. |
|
(17) Event if_fallthrough: |
Falling through to end of if statement. |
|
(18) Event if_end: |
End of if statement. |
|
(19) Event cond_true: |
Condition "_ck_y != NULL", taking true branch. |
|
(20) Event if_fallthrough: |
Falling through to end of if statement. |
|
(21) Event if_end: |
End of if statement. |
|
(22) Event cond_false: |
Condition "0", taking false branch. |
|
(23) Event cond_false: |
Condition "0", taking false branch. |
|
(24) Event cond_true: |
Condition "_ck_x != NULL", taking true branch. |
|
(25) Event cond_true: |
Condition "_ck_y != NULL", taking true branch. |
|
(26) Event cond_true: |
Condition "0 == strcmp(_ck_y, _ck_x)", taking true branch. |
|
(31) Event cond_true: |
Condition "_ck_x != NULL", taking true branch. |
|
(32) Event if_fallthrough: |
Falling through to end of if statement. |
|
(33) Event if_end: |
End of if statement. |
|
(34) Event cond_true: |
Condition "_ck_y != NULL", taking true branch. |
|
(35) Event if_fallthrough: |
Falling through to end of if statement. |
|
(36) Event if_end: |
End of if statement. |
|
(37) Event cond_false: |
Condition "0", taking false branch. |
|
(38) Event cond_false: |
Condition "0", taking false branch. |
|
(39) Event cond_true: |
Condition "_ck_x != NULL", taking true branch. |
|
(40) Event cond_true: |
Condition "_ck_y != NULL", taking true branch. |
|
(41) Event cond_true: |
Condition "0 == strcmp(_ck_y, _ck_x)", taking true branch. |
693 ck_assert_str_eq(word, value);
694 count2++;
|
(27) Event loop: |
Jumping back to the beginning of the loop. |
|
(42) Event loop: |
Jumping back to the beginning of the loop. |
|
(46) Event loop_end: |
Reached end of loop. |
695 }
696 qb_util_stopwatch_stop(sw);
697 fclose(fp);
698
699 secs = qb_util_stopwatch_sec_elapsed_get(sw);
700 ops = (float)count2 / secs;
701 qb_log(LOG_INFO, "%25s %12.2f gets/sec (%d/%fs)\n", test_name, ops, count2, secs);
702
703 /*
704 * time the iteration
705 */
706 count2 = 0;
707 qb_util_stopwatch_start(sw);
708 qb_map_foreach(m, my_counter_traverse, &count2);
709 qb_util_stopwatch_stop(sw);
|
(47) Event cond_true: |
Condition "_ck_x == _ck_y", taking true branch. |
710 ck_assert_int_eq(qb_map_count_get(m), count2);
|
(48) Event zero_return: |
Function call "qb_util_stopwatch_sec_elapsed_get(sw)" returns 0.0. [details] |
|
(49) Event assign: |
Assigning: "secs" = "qb_util_stopwatch_sec_elapsed_get(sw)". |
| Also see events: |
[divide_by_zero] |
711 secs = qb_util_stopwatch_sec_elapsed_get(sw);
|
(50) Event divide_by_zero: |
In expression "(float)count2 / secs", division by expression "secs" which may be zero results in either +infinity, -infinity, or NaN. |
| Also see events: |
[zero_return][assign] |
712 ops = (float)count2 / secs;
713 qb_log(LOG_INFO, "%25s %12.2f iters/sec (%d/%fs)\n", test_name, ops, count2, secs);
714
715 /*
716 * Delete all dictionary entries
717 */
718 fp = fopen("/usr/share/dict/words", "r");
719 qb_util_stopwatch_start(sw);
720 count2 = 0;
721 while (fgets(word, sizeof(word), fp) && count2 < MAX_WORDS) {
722 res = qb_map_rm(m, word);
723 ck_assert_int_eq(res, QB_TRUE);
724 count2++;
725 }
726 qb_util_stopwatch_stop(sw);
727 ck_assert_int_eq(qb_map_count_get(m), 0);
728 fclose(fp);
729
730 secs = qb_util_stopwatch_sec_elapsed_get(sw);
731 ops = (float)count2 / secs;
732 qb_log(LOG_INFO, "%25s %12.2f dels/sec (%d/%fs)\n", test_name, ops, count2, secs);
733 }
734
735 static void test_accents_load(qb_map_t *m, const char* test_name)
736 {
737 int i;
738 int32_t res = 0;
739 int32_t count = 0;
740 int32_t count2;
741 void *value;
742
743 ck_assert(m != NULL);
744 /*
745 * Load accented names
746 */
747 for (i=0; i<sizeof(composers)/sizeof(char*); i++) {
748 qb_map_put(m, strdup(composers[i]), strdup(composers[i]));
749 count++;
750 }
751 ck_assert_int_eq(qb_map_count_get(m), count);
752
753 /*
754 * Verify dictionary produces correct values
755 */
756 count2 = 0;
757 for (i=0; i<sizeof(composers)/sizeof(char*); i++) {
758 value = qb_map_get(m, composers[i]);
759 ck_assert_str_eq(value, composers[i]);
760 count2++;
761 }
762 ck_assert_int_eq(qb_map_count_get(m), count2);
763
764 /*
765 * Delete all dictionary entries
766 */
767 for (i=0; i<sizeof(composers)/sizeof(char*); i++) {
768 res = qb_map_rm(m, composers[i]);
769 ck_assert_int_eq(res, QB_TRUE);
770 }
771 ck_assert_int_eq(qb_map_count_get(m), 0);
772 }
773
774 START_TEST(test_skiplist_simple)
775 {
776 qb_map_t *m = qb_skiplist_create();
777 test_map_simple(m, __func__);
778 }
779 END_TEST
780
781 START_TEST(test_hashtable_simple)
782 {
783 qb_map_t *m = qb_hashtable_create(32);
784 test_map_simple(m, __func__);
785 }
786 END_TEST
787
788 START_TEST(test_trie_simple)
789 {
790 qb_map_t *m = qb_trie_create();
791 test_map_simple(m, __func__);
792 }
793 END_TEST
794
795 START_TEST(test_skiplist_search)
796 {
797 qb_map_t *m = qb_skiplist_create();
798 test_map_search(m);
799 }
800 END_TEST
801
802 START_TEST(test_trie_search)
803 {
804 qb_map_t *m = qb_trie_create();
805 test_map_search(m);
806 }
807 END_TEST
808
809 START_TEST(test_skiplist_remove)
810 {
811 qb_map_t *m = qb_skiplist_create();
812 test_map_remove(m);
813 }
814 END_TEST
815
816 START_TEST(test_hashtable_remove)
817 {
818 qb_map_t *m = qb_hashtable_create(256);
819 test_map_remove(m);
820 }
821 END_TEST
822
823 START_TEST(test_trie_notifications)
824 {
825 qb_map_t *m;
826 m = qb_trie_create();
827 test_map_remove(m);
828 m = qb_trie_create();
829 test_map_notifications_basic(m);
830 m = qb_trie_create();
831 test_map_notifications_prefix(m);
832 m = qb_trie_create();
833 test_map_notifications_free(m);
834 m = qb_trie_create();
835 test_map_notifications_iter(m);
836 }
837 END_TEST
838
839 START_TEST(test_hash_notifications)
840 {
841 qb_map_t *m;
842 m = qb_hashtable_create(256);
843 test_map_notifications_basic(m);
844 m = qb_hashtable_create(256);
845 test_map_notifications_free(m);
846 }
847 END_TEST
848
849 START_TEST(test_skiplist_notifications)
850 {
851 qb_map_t *m;
852 m = qb_skiplist_create();
853 test_map_notifications_basic(m);
854 m = qb_skiplist_create();
855 test_map_notifications_free(m);
856 }
857 END_TEST
858
859 START_TEST(test_skiplist_traverse)
860 {
861 qb_map_t *m;
862 m = qb_skiplist_create();
863 test_map_traverse_ordered(m);
864
865 m = qb_skiplist_create();
866 test_map_traverse_unordered(m);
867 m = qb_skiplist_create();
868 test_map_iter_safety(m, QB_TRUE);
869 }
870 END_TEST
871
872 START_TEST(test_hashtable_traverse)
873 {
874 qb_map_t *m;
875 m = qb_hashtable_create(256);
876 test_map_traverse_unordered(m);
877 m = qb_hashtable_create(256);
878 test_map_iter_safety(m, QB_FALSE);
879 }
880 END_TEST
881
882 START_TEST(test_trie_traverse)
883 {
884 qb_map_t *m;
885 m = qb_trie_create();
886 test_map_traverse_unordered(m);
887 m = qb_trie_create();
888 test_map_iter_safety(m, QB_FALSE);
889 m = qb_trie_create();
890 test_map_iter_prefix(m);
891 }
892 END_TEST
893
894 START_TEST(test_skiplist_load)
895 {
896 qb_map_t *m;
897 if (access("/usr/share/dict/words", R_OK) != 0) {
898 printf("no dict/words - not testing\n");
899 return;
900 }
901 m = qb_skiplist_create();
902 test_map_load(m, __func__);
903 }
904 END_TEST
905
906 START_TEST(test_hashtable_load)
907 {
908 qb_map_t *m;
909 if (access("/usr/share/dict/words", R_OK) != 0) {
910 printf("no dict/words - not testing\n");
911 return;
912 }
913 m = qb_hashtable_create(100000);
914 test_map_load(m, __func__);
915 }
916 END_TEST
917
918 START_TEST(test_trie_load)
919 {
920 qb_map_t *m;
921 if (access("/usr/share/dict/words", R_OK) != 0) {
922 printf("no dict/words - not testing\n");
923 return;
924 }
925 m = qb_trie_create();
926 test_map_load(m, __func__);
927 }
928 END_TEST
929
930 START_TEST(test_skiplist_accents)
931 {
932 qb_map_t *m;
933 m = qb_skiplist_create();
934 test_accents_load(m, __func__);
935 }
936 END_TEST
937
938 START_TEST(test_hashtable_accents)
939 {
940 qb_map_t *m;
941 m = qb_hashtable_create(16);
942 test_accents_load(m, __func__);
943 }
944 END_TEST
945
946 START_TEST(test_trie_accents)
947 {
948 qb_map_t *m;
949 m = qb_trie_create();
950 test_accents_load(m, __func__);
951 }
952 END_TEST
953
954
955 /*
956 * From Honza: https://github.com/asalkeld/libqb/issues/44
957 */
958 START_TEST(test_trie_partial_iterate)
959 {
960 qb_map_t *map;
961 qb_map_iter_t *iter;
962 const char *res;
963 char *item;
964 int rc;
965
966 ck_assert((map = qb_trie_create()) != NULL);
967 qb_map_put(map, strdup("testobj.testkey"), strdup("one"));
968 qb_map_put(map, strdup("testobj.testkey2"), strdup("two"));
969
970 iter = qb_map_pref_iter_create(map, "testobj.");
971 ck_assert(iter != NULL);
972 res = qb_map_iter_next(iter, (void **)&item);
973 fprintf(stderr, "%s = %s\n", res, item);
974 qb_map_iter_free(iter);
975
976 item = qb_map_get(map, "testobj.testkey");
977 ck_assert_str_eq(item, "one");
978
979 rc = qb_map_rm(map, "testobj.testkey");
980 ck_assert(rc == QB_TRUE);
981
982 item = qb_map_get(map, "testobj.testkey");
983 ck_assert(item == NULL);
984
985 }
986 END_TEST
987
988
989 static Suite *
990 map_suite(void)
991 {
992 TCase *tc;
993 Suite *s = suite_create("qb_map");
994
995 add_tcase(s, tc, test_skiplist_simple, 0);
996 add_tcase(s, tc, test_hashtable_simple, 0);
997 add_tcase(s, tc, test_trie_simple, 0);
998 add_tcase(s, tc, test_trie_partial_iterate, 0);
999 add_tcase(s, tc, test_skiplist_remove, 0);
1000 add_tcase(s, tc, test_hashtable_remove, 0);
1001 add_tcase(s, tc, test_trie_notifications, 0);
1002 add_tcase(s, tc, test_hash_notifications, 0);
1003 add_tcase(s, tc, test_skiplist_notifications, 0);
1004 add_tcase(s, tc, test_skiplist_search, 0);
1005
1006 /*
1007 * No hashtable_search as it assumes an ordered
1008 * collection
1009 */
1010 add_tcase(s, tc, test_trie_search, 0);
1011 add_tcase(s, tc, test_skiplist_traverse, 0);
1012 add_tcase(s, tc, test_hashtable_traverse, 0);
1013 add_tcase(s, tc, test_trie_traverse, 0);
1014 add_tcase(s, tc, test_skiplist_load, 30);
1015 add_tcase(s, tc, test_hashtable_load, 30);
1016 add_tcase(s, tc, test_trie_load, 30);
1017
1018 add_tcase(s, tc, test_skiplist_accents, 0);
1019 add_tcase(s, tc, test_hashtable_accents, 0);
1020 add_tcase(s, tc, test_trie_accents, 0);
1021
1022 return s;
1023 }
1024
1025 int32_t
1026 main(void)
1027 {
1028 int32_t number_failed;
1029
1030 Suite *s = map_suite();
1031 SRunner *sr = srunner_create(s);
1032
1033 qb_log_init("check", LOG_USER, LOG_EMERG);
1034 atexit(qb_log_fini);
1035 qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
1036 qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
1037 QB_LOG_FILTER_FILE, "*", LOG_INFO);
1038 qb_log_format_set(QB_LOG_STDERR, "%f:%l %p %b");
1039 qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
1040
1041 srunner_run_all(sr, CK_VERBOSE);
1042 number_failed = srunner_ntests_failed(sr);
1043 srunner_free(sr);
1044 return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
1045 }
1046