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);
711  		secs = qb_util_stopwatch_sec_elapsed_get(sw);
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  		 */
(48) Event returned_null: "fopen" returns "NULL".
(49) Event var_assigned: Assigning: "fp" = "NULL" return value from "fopen".
Also see events: [dereference]
718  		fp = fopen("/usr/share/dict/words", "r");
719  		qb_util_stopwatch_start(sw);
720  		count2 = 0;
(50) Event dereference: Passing null pointer "fp" to "fgets", which dereferences it.
Also see events: [returned_null][var_assigned]
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