1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
6 #include "stdio-util.h"
7 #include "string-util.h"
12 void test_hashmap_funcs(void);
14 static void test_hashmap_replace(void) {
16 char *val1
, *val2
, *val3
, *val4
, *val5
, *r
;
18 log_info("/* %s */", __func__
);
20 m
= hashmap_new(&string_hash_ops
);
22 val1
= strdup("val1");
24 val2
= strdup("val2");
26 val3
= strdup("val3");
28 val4
= strdup("val4");
30 val5
= strdup("val5");
33 hashmap_put(m
, "key 1", val1
);
34 hashmap_put(m
, "key 2", val2
);
35 hashmap_put(m
, "key 3", val3
);
36 hashmap_put(m
, "key 4", val4
);
38 hashmap_replace(m
, "key 3", val1
);
39 r
= hashmap_get(m
, "key 3");
40 assert_se(streq(r
, "val1"));
42 hashmap_replace(m
, "key 5", val5
);
43 r
= hashmap_get(m
, "key 5");
44 assert_se(streq(r
, "val5"));
54 static void test_hashmap_copy(void) {
56 char *val1
, *val2
, *val3
, *val4
, *r
;
58 log_info("/* %s */", __func__
);
60 val1
= strdup("val1");
62 val2
= strdup("val2");
64 val3
= strdup("val3");
66 val4
= strdup("val4");
69 m
= hashmap_new(&string_hash_ops
);
71 hashmap_put(m
, "key 1", val1
);
72 hashmap_put(m
, "key 2", val2
);
73 hashmap_put(m
, "key 3", val3
);
74 hashmap_put(m
, "key 4", val4
);
76 copy
= hashmap_copy(m
);
78 r
= hashmap_get(copy
, "key 1");
79 assert_se(streq(r
, "val1"));
80 r
= hashmap_get(copy
, "key 2");
81 assert_se(streq(r
, "val2"));
82 r
= hashmap_get(copy
, "key 3");
83 assert_se(streq(r
, "val3"));
84 r
= hashmap_get(copy
, "key 4");
85 assert_se(streq(r
, "val4"));
87 hashmap_free_free(copy
);
91 static void test_hashmap_get_strv(void) {
94 char *val1
, *val2
, *val3
, *val4
;
96 log_info("/* %s */", __func__
);
98 val1
= strdup("val1");
100 val2
= strdup("val2");
102 val3
= strdup("val3");
104 val4
= strdup("val4");
107 m
= hashmap_new(&string_hash_ops
);
109 hashmap_put(m
, "key 1", val1
);
110 hashmap_put(m
, "key 2", val2
);
111 hashmap_put(m
, "key 3", val3
);
112 hashmap_put(m
, "key 4", val4
);
114 strv
= hashmap_get_strv(m
);
117 strv
= strv_sort(strv
);
120 assert_se(streq(strv
[0], "val1"));
121 assert_se(streq(strv
[1], "val2"));
122 assert_se(streq(strv
[2], "val3"));
123 assert_se(streq(strv
[3], "val4"));
130 static void test_hashmap_move_one(void) {
132 char *val1
, *val2
, *val3
, *val4
, *r
;
134 log_info("/* %s */", __func__
);
136 val1
= strdup("val1");
138 val2
= strdup("val2");
140 val3
= strdup("val3");
142 val4
= strdup("val4");
145 m
= hashmap_new(&string_hash_ops
);
146 n
= hashmap_new(&string_hash_ops
);
148 hashmap_put(m
, "key 1", val1
);
149 hashmap_put(m
, "key 2", val2
);
150 hashmap_put(m
, "key 3", val3
);
151 hashmap_put(m
, "key 4", val4
);
153 assert_se(hashmap_move_one(n
, NULL
, "key 3") == -ENOENT
);
154 assert_se(hashmap_move_one(n
, m
, "key 5") == -ENOENT
);
155 assert_se(hashmap_move_one(n
, m
, "key 3") == 0);
156 assert_se(hashmap_move_one(n
, m
, "key 4") == 0);
158 r
= hashmap_get(n
, "key 3");
159 assert_se(r
&& streq(r
, "val3"));
160 r
= hashmap_get(n
, "key 4");
161 assert_se(r
&& streq(r
, "val4"));
162 r
= hashmap_get(m
, "key 3");
165 assert_se(hashmap_move_one(n
, m
, "key 3") == -EEXIST
);
167 hashmap_free_free(m
);
168 hashmap_free_free(n
);
171 static void test_hashmap_move(void) {
173 char *val1
, *val2
, *val3
, *val4
, *r
;
175 log_info("/* %s */", __func__
);
177 val1
= strdup("val1");
179 val2
= strdup("val2");
181 val3
= strdup("val3");
183 val4
= strdup("val4");
186 m
= hashmap_new(&string_hash_ops
);
187 n
= hashmap_new(&string_hash_ops
);
189 hashmap_put(n
, "key 1", strdup(val1
));
190 hashmap_put(m
, "key 1", val1
);
191 hashmap_put(m
, "key 2", val2
);
192 hashmap_put(m
, "key 3", val3
);
193 hashmap_put(m
, "key 4", val4
);
195 assert_se(hashmap_move(n
, NULL
) == 0);
196 assert_se(hashmap_move(n
, m
) == 0);
198 assert_se(hashmap_size(m
) == 1);
199 r
= hashmap_get(m
, "key 1");
200 assert_se(r
&& streq(r
, "val1"));
202 r
= hashmap_get(n
, "key 1");
203 assert_se(r
&& streq(r
, "val1"));
204 r
= hashmap_get(n
, "key 2");
205 assert_se(r
&& streq(r
, "val2"));
206 r
= hashmap_get(n
, "key 3");
207 assert_se(r
&& streq(r
, "val3"));
208 r
= hashmap_get(n
, "key 4");
209 assert_se(r
&& streq(r
, "val4"));
211 hashmap_free_free(m
);
212 hashmap_free_free(n
);
215 static void test_hashmap_update(void) {
217 char *val1
, *val2
, *r
;
219 log_info("/* %s */", __func__
);
221 m
= hashmap_new(&string_hash_ops
);
222 val1
= strdup("old_value");
224 val2
= strdup("new_value");
227 hashmap_put(m
, "key 1", val1
);
228 r
= hashmap_get(m
, "key 1");
229 assert_se(streq(r
, "old_value"));
231 assert_se(hashmap_update(m
, "key 2", val2
) == -ENOENT
);
232 r
= hashmap_get(m
, "key 1");
233 assert_se(streq(r
, "old_value"));
235 assert_se(hashmap_update(m
, "key 1", val2
) == 0);
236 r
= hashmap_get(m
, "key 1");
237 assert_se(streq(r
, "new_value"));
244 static void test_hashmap_put(void) {
246 int valid_hashmap_put
;
247 void *val1
= (void*) "val 1";
248 void *val2
= (void*) "val 2";
249 _cleanup_free_
char* key1
= NULL
;
251 log_info("/* %s */", __func__
);
253 assert_se(hashmap_ensure_allocated(&m
, &string_hash_ops
) >= 0);
256 valid_hashmap_put
= hashmap_put(m
, "key 1", val1
);
257 assert_se(valid_hashmap_put
== 1);
258 assert_se(hashmap_put(m
, "key 1", val1
) == 0);
259 assert_se(hashmap_put(m
, "key 1", val2
) == -EEXIST
);
260 key1
= strdup("key 1");
261 assert_se(hashmap_put(m
, key1
, val1
) == 0);
262 assert_se(hashmap_put(m
, key1
, val2
) == -EEXIST
);
267 static void test_hashmap_remove(void) {
268 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
271 log_info("/* %s */", __func__
);
273 r
= hashmap_remove(NULL
, "key 1");
274 assert_se(r
== NULL
);
276 m
= hashmap_new(&string_hash_ops
);
279 r
= hashmap_remove(m
, "no such key");
280 assert_se(r
== NULL
);
282 hashmap_put(m
, "key 1", (void*) "val 1");
283 hashmap_put(m
, "key 2", (void*) "val 2");
285 r
= hashmap_remove(m
, "key 1");
286 assert_se(streq(r
, "val 1"));
288 r
= hashmap_get(m
, "key 2");
289 assert_se(streq(r
, "val 2"));
290 assert_se(!hashmap_get(m
, "key 1"));
293 static void test_hashmap_remove2(void) {
294 _cleanup_hashmap_free_free_free_ Hashmap
*m
= NULL
;
295 char key1
[] = "key 1";
296 char key2
[] = "key 2";
297 char val1
[] = "val 1";
298 char val2
[] = "val 2";
301 log_info("/* %s */", __func__
);
303 r
= hashmap_remove2(NULL
, "key 1", &r2
);
304 assert_se(r
== NULL
);
306 m
= hashmap_new(&string_hash_ops
);
309 r
= hashmap_remove2(m
, "no such key", &r2
);
310 assert_se(r
== NULL
);
312 hashmap_put(m
, strdup(key1
), strdup(val1
));
313 hashmap_put(m
, strdup(key2
), strdup(val2
));
315 r
= hashmap_remove2(m
, key1
, &r2
);
316 assert_se(streq(r
, val1
));
317 assert_se(streq(r2
, key1
));
321 r
= hashmap_get(m
, key2
);
322 assert_se(streq(r
, val2
));
323 assert_se(!hashmap_get(m
, key1
));
326 static void test_hashmap_remove_value(void) {
327 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
330 char val1
[] = "val 1";
331 char val2
[] = "val 2";
333 log_info("/* %s */", __func__
);
335 r
= hashmap_remove_value(NULL
, "key 1", val1
);
336 assert_se(r
== NULL
);
338 m
= hashmap_new(&string_hash_ops
);
341 r
= hashmap_remove_value(m
, "key 1", val1
);
342 assert_se(r
== NULL
);
344 hashmap_put(m
, "key 1", val1
);
345 hashmap_put(m
, "key 2", val2
);
347 r
= hashmap_remove_value(m
, "key 1", val1
);
348 assert_se(streq(r
, "val 1"));
350 r
= hashmap_get(m
, "key 2");
351 assert_se(streq(r
, "val 2"));
352 assert_se(!hashmap_get(m
, "key 1"));
354 r
= hashmap_remove_value(m
, "key 2", val1
);
355 assert_se(r
== NULL
);
357 r
= hashmap_get(m
, "key 2");
358 assert_se(streq(r
, "val 2"));
359 assert_se(!hashmap_get(m
, "key 1"));
362 static void test_hashmap_remove_and_put(void) {
363 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
367 log_info("/* %s */", __func__
);
369 m
= hashmap_new(&string_hash_ops
);
372 valid
= hashmap_remove_and_put(m
, "invalid key", "new key", NULL
);
373 assert_se(valid
== -ENOENT
);
375 valid
= hashmap_put(m
, "key 1", (void*) (const char *) "val 1");
376 assert_se(valid
== 1);
378 valid
= hashmap_remove_and_put(NULL
, "key 1", "key 2", (void*) (const char *) "val 2");
379 assert_se(valid
== -ENOENT
);
381 valid
= hashmap_remove_and_put(m
, "key 1", "key 2", (void*) (const char *) "val 2");
382 assert_se(valid
== 0);
384 r
= hashmap_get(m
, "key 2");
385 assert_se(streq(r
, "val 2"));
386 assert_se(!hashmap_get(m
, "key 1"));
388 valid
= hashmap_put(m
, "key 3", (void*) (const char *) "val 3");
389 assert_se(valid
== 1);
390 valid
= hashmap_remove_and_put(m
, "key 3", "key 2", (void*) (const char *) "val 2");
391 assert_se(valid
== -EEXIST
);
394 static void test_hashmap_remove_and_replace(void) {
395 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
397 void *key1
= UINT_TO_PTR(1);
398 void *key2
= UINT_TO_PTR(2);
399 void *key3
= UINT_TO_PTR(3);
403 log_info("/* %s */", __func__
);
405 m
= hashmap_new(&trivial_hash_ops
);
408 valid
= hashmap_remove_and_replace(m
, key1
, key2
, NULL
);
409 assert_se(valid
== -ENOENT
);
411 valid
= hashmap_put(m
, key1
, key1
);
412 assert_se(valid
== 1);
414 valid
= hashmap_remove_and_replace(NULL
, key1
, key2
, key2
);
415 assert_se(valid
== -ENOENT
);
417 valid
= hashmap_remove_and_replace(m
, key1
, key2
, key2
);
418 assert_se(valid
== 0);
420 r
= hashmap_get(m
, key2
);
421 assert_se(r
== key2
);
422 assert_se(!hashmap_get(m
, key1
));
424 valid
= hashmap_put(m
, key3
, key3
);
425 assert_se(valid
== 1);
426 valid
= hashmap_remove_and_replace(m
, key3
, key2
, key2
);
427 assert_se(valid
== 0);
428 r
= hashmap_get(m
, key2
);
429 assert_se(r
== key2
);
430 assert_se(!hashmap_get(m
, key3
));
432 /* Repeat this test several times to increase the chance of hitting
433 * the less likely case in hashmap_remove_and_replace where it
434 * compensates for the backward shift. */
435 for (i
= 0; i
< 20; i
++) {
438 for (j
= 1; j
< 7; j
++)
439 hashmap_put(m
, UINT_TO_PTR(10*i
+ j
), UINT_TO_PTR(10*i
+ j
));
440 valid
= hashmap_remove_and_replace(m
, UINT_TO_PTR(10*i
+ 1),
441 UINT_TO_PTR(10*i
+ 2),
442 UINT_TO_PTR(10*i
+ 2));
443 assert_se(valid
== 0);
444 assert_se(!hashmap_get(m
, UINT_TO_PTR(10*i
+ 1)));
445 for (j
= 2; j
< 7; j
++) {
446 r
= hashmap_get(m
, UINT_TO_PTR(10*i
+ j
));
447 assert_se(r
== UINT_TO_PTR(10*i
+ j
));
452 static void test_hashmap_ensure_allocated(void) {
456 log_info("/* %s */", __func__
);
458 m
= hashmap_new(&string_hash_ops
);
460 valid_hashmap
= hashmap_ensure_allocated(&m
, &string_hash_ops
);
461 assert_se(valid_hashmap
== 0);
467 static void test_hashmap_foreach_key(void) {
470 bool key_found
[] = { false, false, false, false };
473 static const char key_table
[] =
479 log_info("/* %s */", __func__
);
481 m
= hashmap_new(&string_hash_ops
);
483 NULSTR_FOREACH(key
, key_table
)
484 hashmap_put(m
, key
, (void*) (const char*) "my dummy val");
486 HASHMAP_FOREACH_KEY(s
, key
, m
, i
) {
488 if (!key_found
[0] && streq(key
, "key 1"))
490 else if (!key_found
[1] && streq(key
, "key 2"))
492 else if (!key_found
[2] && streq(key
, "key 3"))
494 else if (!key_found
[3] && streq(key
, "fail"))
499 assert_se(key_found
[0] && key_found
[1] && key_found
[2] && !key_found
[3]);
504 static void test_hashmap_foreach(void) {
507 bool value_found
[] = { false, false, false, false };
508 char *val1
, *val2
, *val3
, *val4
, *s
;
511 log_info("/* %s */", __func__
);
513 val1
= strdup("my val1");
515 val2
= strdup("my val2");
517 val3
= strdup("my val3");
519 val4
= strdup("my val4");
525 HASHMAP_FOREACH(s
, m
, i
)
527 assert_se(count
== 0);
529 m
= hashmap_new(&string_hash_ops
);
532 HASHMAP_FOREACH(s
, m
, i
)
534 assert_se(count
== 0);
536 hashmap_put(m
, "Key 1", val1
);
537 hashmap_put(m
, "Key 2", val2
);
538 hashmap_put(m
, "Key 3", val3
);
539 hashmap_put(m
, "Key 4", val4
);
541 HASHMAP_FOREACH(s
, m
, i
) {
542 if (!value_found
[0] && streq(s
, val1
))
543 value_found
[0] = true;
544 else if (!value_found
[1] && streq(s
, val2
))
545 value_found
[1] = true;
546 else if (!value_found
[2] && streq(s
, val3
))
547 value_found
[2] = true;
548 else if (!value_found
[3] && streq(s
, val4
))
549 value_found
[3] = true;
553 assert_se(value_found
[0] && value_found
[1] && value_found
[2] && value_found
[3]);
555 hashmap_free_free(m
);
558 static void test_hashmap_merge(void) {
561 char *val1
, *val2
, *val3
, *val4
, *r
;
563 log_info("/* %s */", __func__
);
565 val1
= strdup("my val1");
567 val2
= strdup("my val2");
569 val3
= strdup("my val3");
571 val4
= strdup("my val4");
574 n
= hashmap_new(&string_hash_ops
);
575 m
= hashmap_new(&string_hash_ops
);
577 hashmap_put(m
, "Key 1", val1
);
578 hashmap_put(m
, "Key 2", val2
);
579 hashmap_put(n
, "Key 3", val3
);
580 hashmap_put(n
, "Key 4", val4
);
582 assert_se(hashmap_merge(m
, n
) == 0);
583 r
= hashmap_get(m
, "Key 3");
584 assert_se(r
&& streq(r
, "my val3"));
585 r
= hashmap_get(m
, "Key 4");
586 assert_se(r
&& streq(r
, "my val4"));
591 hashmap_free_free(m
);
594 static void test_hashmap_contains(void) {
598 log_info("/* %s */", __func__
);
600 val1
= strdup("my val");
603 m
= hashmap_new(&string_hash_ops
);
605 assert_se(!hashmap_contains(m
, "Key 1"));
606 hashmap_put(m
, "Key 1", val1
);
607 assert_se(hashmap_contains(m
, "Key 1"));
608 assert_se(!hashmap_contains(m
, "Key 2"));
610 assert_se(!hashmap_contains(NULL
, "Key 1"));
613 hashmap_free_free(m
);
616 static void test_hashmap_isempty(void) {
620 log_info("/* %s */", __func__
);
622 val1
= strdup("my val");
625 m
= hashmap_new(&string_hash_ops
);
627 assert_se(hashmap_isempty(m
));
628 hashmap_put(m
, "Key 1", val1
);
629 assert_se(!hashmap_isempty(m
));
632 hashmap_free_free(m
);
635 static void test_hashmap_size(void) {
637 char *val1
, *val2
, *val3
, *val4
;
639 log_info("/* %s */", __func__
);
641 val1
= strdup("my val");
643 val2
= strdup("my val");
645 val3
= strdup("my val");
647 val4
= strdup("my val");
650 assert_se(hashmap_size(NULL
) == 0);
651 assert_se(hashmap_buckets(NULL
) == 0);
653 m
= hashmap_new(&string_hash_ops
);
655 hashmap_put(m
, "Key 1", val1
);
656 hashmap_put(m
, "Key 2", val2
);
657 hashmap_put(m
, "Key 3", val3
);
658 hashmap_put(m
, "Key 4", val4
);
661 assert_se(hashmap_size(m
) == 4);
662 assert_se(hashmap_buckets(m
) >= 4);
663 hashmap_free_free(m
);
666 static void test_hashmap_get(void) {
671 log_info("/* %s */", __func__
);
673 val
= strdup("my val");
676 r
= hashmap_get(NULL
, "Key 1");
677 assert_se(r
== NULL
);
679 m
= hashmap_new(&string_hash_ops
);
681 hashmap_put(m
, "Key 1", val
);
683 r
= hashmap_get(m
, "Key 1");
684 assert_se(streq(r
, val
));
686 r
= hashmap_get(m
, "no such key");
687 assert_se(r
== NULL
);
690 hashmap_free_free(m
);
693 static void test_hashmap_get2(void) {
697 char key_orig
[] = "Key 1";
700 log_info("/* %s */", __func__
);
702 val
= strdup("my val");
705 key_copy
= strdup(key_orig
);
708 r
= hashmap_get2(NULL
, key_orig
, &key_copy
);
709 assert_se(r
== NULL
);
711 m
= hashmap_new(&string_hash_ops
);
713 hashmap_put(m
, key_copy
, val
);
716 r
= hashmap_get2(m
, key_orig
, &key_copy
);
717 assert_se(streq(r
, val
));
718 assert_se(key_orig
!= key_copy
);
719 assert_se(streq(key_orig
, key_copy
));
721 r
= hashmap_get2(m
, "no such key", NULL
);
722 assert_se(r
== NULL
);
725 hashmap_free_free_free(m
);
728 static void crippled_hashmap_func(const void *p
, struct siphash
*state
) {
729 return trivial_hash_func(INT_TO_PTR(PTR_TO_INT(p
) & 0xff), state
);
732 static const struct hash_ops crippled_hashmap_ops
= {
733 .hash
= crippled_hashmap_func
,
734 .compare
= trivial_compare_func
,
737 static void test_hashmap_many(void) {
741 bool slow
= slow_tests_enabled();
744 const struct hash_ops
*ops
;
747 { "trivial_hashmap_ops", NULL
, slow
? 1 << 20 : 240 },
748 { "crippled_hashmap_ops", &crippled_hashmap_ops
, slow
? 1 << 14 : 140 },
751 log_info("/* %s (%s) */", __func__
, slow
? "slow" : "fast");
753 for (j
= 0; j
< ELEMENTSOF(tests
); j
++) {
754 usec_t ts
= now(CLOCK_MONOTONIC
), n
;
755 char b
[FORMAT_TIMESPAN_MAX
];
757 assert_se(h
= hashmap_new(tests
[j
].ops
));
759 for (i
= 1; i
< tests
[j
].n_entries
*3; i
+=3) {
760 assert_se(hashmap_put(h
, UINT_TO_PTR(i
), UINT_TO_PTR(i
)) >= 0);
761 assert_se(PTR_TO_UINT(hashmap_get(h
, UINT_TO_PTR(i
))) == i
);
764 for (i
= 1; i
< tests
[j
].n_entries
*3; i
++)
765 assert_se(hashmap_contains(h
, UINT_TO_PTR(i
)) == (i
% 3 == 1));
767 log_info("%s %u <= %u * 0.8 = %g",
768 tests
[j
].title
, hashmap_size(h
), hashmap_buckets(h
), hashmap_buckets(h
) * 0.8);
770 assert_se(hashmap_size(h
) <= hashmap_buckets(h
) * 0.8);
771 assert_se(hashmap_size(h
) == tests
[j
].n_entries
);
773 while (!hashmap_isempty(h
)) {
774 k
= hashmap_first_key(h
);
775 v
= hashmap_remove(h
, k
);
781 n
= now(CLOCK_MONOTONIC
);
782 log_info("test took %s", format_timespan(b
, sizeof b
, n
- ts
, 0));
786 extern unsigned custom_counter
;
787 extern const struct hash_ops boring_hash_ops
, custom_hash_ops
;
789 static void test_hashmap_free(void) {
791 bool slow
= slow_tests_enabled();
793 char b
[FORMAT_TIMESPAN_MAX
];
794 unsigned n_entries
= slow
? 1 << 20 : 240;
798 const struct hash_ops
*ops
;
799 unsigned expect_counter
;
801 { "string_hash_ops", &boring_hash_ops
, 2 * n_entries
},
802 { "custom_free_hash_ops", &custom_hash_ops
, 0 },
805 log_info("/* %s (%s, %u entries) */", __func__
, slow
? "slow" : "fast", n_entries
);
807 for (unsigned j
= 0; j
< ELEMENTSOF(tests
); j
++) {
808 ts
= now(CLOCK_MONOTONIC
);
809 assert_se(h
= hashmap_new(tests
[j
].ops
));
812 for (unsigned i
= 0; i
< n_entries
; i
++) {
813 char s
[DECIMAL_STR_MAX(unsigned)];
816 xsprintf(s
, "%u", i
);
817 assert_se(k
= strdup(s
));
818 assert_se(v
= strdup(s
));
821 assert_se(hashmap_put(h
, k
, v
) >= 0);
826 n
= now(CLOCK_MONOTONIC
);
827 log_info("%s test took %s", tests
[j
].title
, format_timespan(b
, sizeof b
, n
- ts
, 0));
829 assert_se(custom_counter
== tests
[j
].expect_counter
);
833 static void test_hashmap_first(void) {
834 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
836 log_info("/* %s */", __func__
);
838 m
= hashmap_new(&string_hash_ops
);
841 assert_se(!hashmap_first(m
));
842 assert_se(hashmap_put(m
, "key 1", (void*) "val 1") == 1);
843 assert_se(streq(hashmap_first(m
), "val 1"));
844 assert_se(hashmap_put(m
, "key 2", (void*) "val 2") == 1);
846 assert_se(streq(hashmap_first(m
), "val 1"));
847 assert_se(hashmap_remove(m
, "key 1"));
848 assert_se(streq(hashmap_first(m
), "val 2"));
852 static void test_hashmap_first_key(void) {
853 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
855 log_info("/* %s */", __func__
);
857 m
= hashmap_new(&string_hash_ops
);
860 assert_se(!hashmap_first_key(m
));
861 assert_se(hashmap_put(m
, "key 1", NULL
) == 1);
862 assert_se(streq(hashmap_first_key(m
), "key 1"));
863 assert_se(hashmap_put(m
, "key 2", NULL
) == 1);
865 assert_se(streq(hashmap_first_key(m
), "key 1"));
866 assert_se(hashmap_remove(m
, "key 1") == NULL
);
867 assert_se(streq(hashmap_first_key(m
), "key 2"));
871 static void test_hashmap_steal_first_key(void) {
872 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
874 log_info("/* %s */", __func__
);
876 m
= hashmap_new(&string_hash_ops
);
879 assert_se(!hashmap_steal_first_key(m
));
880 assert_se(hashmap_put(m
, "key 1", NULL
) == 1);
881 assert_se(streq(hashmap_steal_first_key(m
), "key 1"));
883 assert_se(hashmap_isempty(m
));
886 static void test_hashmap_steal_first(void) {
887 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
891 log_info("/* %s */", __func__
);
893 m
= hashmap_new(&string_hash_ops
);
896 assert_se(hashmap_put(m
, "key 1", (void*) "1") == 1);
897 assert_se(hashmap_put(m
, "key 2", (void*) "22") == 1);
898 assert_se(hashmap_put(m
, "key 3", (void*) "333") == 1);
900 while ((val
= hashmap_steal_first(m
)))
901 seen
[strlen(val
) - 1]++;
903 assert_se(seen
[0] == 1 && seen
[1] == 1 && seen
[2] == 1);
905 assert_se(hashmap_isempty(m
));
908 static void test_hashmap_clear_free_free(void) {
909 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
911 log_info("/* %s */", __func__
);
913 m
= hashmap_new(&string_hash_ops
);
916 assert_se(hashmap_put(m
, strdup("key 1"), NULL
) == 1);
917 assert_se(hashmap_put(m
, strdup("key 2"), NULL
) == 1);
918 assert_se(hashmap_put(m
, strdup("key 3"), NULL
) == 1);
920 hashmap_clear_free_free(m
);
921 assert_se(hashmap_isempty(m
));
923 assert_se(hashmap_put(m
, strdup("key 1"), strdup("value 1")) == 1);
924 assert_se(hashmap_put(m
, strdup("key 2"), strdup("value 2")) == 1);
925 assert_se(hashmap_put(m
, strdup("key 3"), strdup("value 3")) == 1);
927 hashmap_clear_free_free(m
);
928 assert_se(hashmap_isempty(m
));
931 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(test_hash_ops_key
, char, string_hash_func
, string_compare_func
, free
);
932 DEFINE_PRIVATE_HASH_OPS_FULL(test_hash_ops_full
, char, string_hash_func
, string_compare_func
, free
, char, free
);
934 static void test_hashmap_clear_free_with_destructor(void) {
935 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
937 log_info("/* %s */", __func__
);
939 m
= hashmap_new(&test_hash_ops_key
);
942 assert_se(hashmap_put(m
, strdup("key 1"), NULL
) == 1);
943 assert_se(hashmap_put(m
, strdup("key 2"), NULL
) == 1);
944 assert_se(hashmap_put(m
, strdup("key 3"), NULL
) == 1);
946 hashmap_clear_free(m
);
947 assert_se(hashmap_isempty(m
));
950 m
= hashmap_new(&test_hash_ops_full
);
953 assert_se(hashmap_put(m
, strdup("key 1"), strdup("value 1")) == 1);
954 assert_se(hashmap_put(m
, strdup("key 2"), strdup("value 2")) == 1);
955 assert_se(hashmap_put(m
, strdup("key 3"), strdup("value 3")) == 1);
957 hashmap_clear_free(m
);
958 assert_se(hashmap_isempty(m
));
961 static void test_hashmap_reserve(void) {
962 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
964 log_info("/* %s */", __func__
);
966 m
= hashmap_new(&string_hash_ops
);
968 assert_se(hashmap_reserve(m
, 1) == 0);
969 assert_se(hashmap_buckets(m
) < 1000);
970 assert_se(hashmap_reserve(m
, 1000) == 0);
971 assert_se(hashmap_buckets(m
) >= 1000);
972 assert_se(hashmap_isempty(m
));
974 assert_se(hashmap_put(m
, "key 1", (void*) "val 1") == 1);
976 assert_se(hashmap_reserve(m
, UINT_MAX
) == -ENOMEM
);
977 assert_se(hashmap_reserve(m
, UINT_MAX
- 1) == -ENOMEM
);
980 void test_hashmap_funcs(void) {
981 log_parse_environment();
985 test_hashmap_get_strv();
986 test_hashmap_move_one();
988 test_hashmap_replace();
989 test_hashmap_update();
991 test_hashmap_remove();
992 test_hashmap_remove2();
993 test_hashmap_remove_value();
994 test_hashmap_remove_and_put();
995 test_hashmap_remove_and_replace();
996 test_hashmap_ensure_allocated();
997 test_hashmap_foreach();
998 test_hashmap_foreach_key();
999 test_hashmap_contains();
1000 test_hashmap_merge();
1001 test_hashmap_isempty();
1003 test_hashmap_get2();
1004 test_hashmap_size();
1005 test_hashmap_many();
1006 test_hashmap_free();
1007 test_hashmap_first();
1008 test_hashmap_first_key();
1009 test_hashmap_steal_first_key();
1010 test_hashmap_steal_first();
1011 test_hashmap_clear_free_free();
1012 test_hashmap_clear_free_with_destructor();
1013 test_hashmap_reserve();