1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "alloc-util.h"
6 #include "nulstr-util.h"
7 #include "stdio-util.h"
8 #include "string-util.h"
10 #include "time-util.h"
13 void test_hashmap_funcs(void);
15 static void test_hashmap_replace(void) {
17 char *val1
, *val2
, *val3
, *val4
, *val5
, *r
;
19 log_info("/* %s */", __func__
);
21 m
= hashmap_new(&string_hash_ops
);
23 val1
= strdup("val1");
25 val2
= strdup("val2");
27 val3
= strdup("val3");
29 val4
= strdup("val4");
31 val5
= strdup("val5");
34 hashmap_put(m
, "key 1", val1
);
35 hashmap_put(m
, "key 2", val2
);
36 hashmap_put(m
, "key 3", val3
);
37 hashmap_put(m
, "key 4", val4
);
39 hashmap_replace(m
, "key 3", val1
);
40 r
= hashmap_get(m
, "key 3");
41 assert_se(streq(r
, "val1"));
43 hashmap_replace(m
, "key 5", val5
);
44 r
= hashmap_get(m
, "key 5");
45 assert_se(streq(r
, "val5"));
55 static void test_hashmap_copy(void) {
57 char *val1
, *val2
, *val3
, *val4
, *r
;
59 log_info("/* %s */", __func__
);
61 val1
= strdup("val1");
63 val2
= strdup("val2");
65 val3
= strdup("val3");
67 val4
= strdup("val4");
70 m
= hashmap_new(&string_hash_ops
);
72 hashmap_put(m
, "key 1", val1
);
73 hashmap_put(m
, "key 2", val2
);
74 hashmap_put(m
, "key 3", val3
);
75 hashmap_put(m
, "key 4", val4
);
77 copy
= hashmap_copy(m
);
79 r
= hashmap_get(copy
, "key 1");
80 assert_se(streq(r
, "val1"));
81 r
= hashmap_get(copy
, "key 2");
82 assert_se(streq(r
, "val2"));
83 r
= hashmap_get(copy
, "key 3");
84 assert_se(streq(r
, "val3"));
85 r
= hashmap_get(copy
, "key 4");
86 assert_se(streq(r
, "val4"));
88 hashmap_free_free(copy
);
92 static void test_hashmap_get_strv(void) {
95 char *val1
, *val2
, *val3
, *val4
;
97 log_info("/* %s */", __func__
);
99 val1
= strdup("val1");
101 val2
= strdup("val2");
103 val3
= strdup("val3");
105 val4
= strdup("val4");
108 m
= hashmap_new(&string_hash_ops
);
110 hashmap_put(m
, "key 1", val1
);
111 hashmap_put(m
, "key 2", val2
);
112 hashmap_put(m
, "key 3", val3
);
113 hashmap_put(m
, "key 4", val4
);
115 strv
= hashmap_get_strv(m
);
118 strv
= strv_sort(strv
);
121 assert_se(streq(strv
[0], "val1"));
122 assert_se(streq(strv
[1], "val2"));
123 assert_se(streq(strv
[2], "val3"));
124 assert_se(streq(strv
[3], "val4"));
131 static void test_hashmap_move_one(void) {
133 char *val1
, *val2
, *val3
, *val4
, *r
;
135 log_info("/* %s */", __func__
);
137 val1
= strdup("val1");
139 val2
= strdup("val2");
141 val3
= strdup("val3");
143 val4
= strdup("val4");
146 m
= hashmap_new(&string_hash_ops
);
147 n
= hashmap_new(&string_hash_ops
);
149 hashmap_put(m
, "key 1", val1
);
150 hashmap_put(m
, "key 2", val2
);
151 hashmap_put(m
, "key 3", val3
);
152 hashmap_put(m
, "key 4", val4
);
154 assert_se(hashmap_move_one(n
, NULL
, "key 3") == -ENOENT
);
155 assert_se(hashmap_move_one(n
, m
, "key 5") == -ENOENT
);
156 assert_se(hashmap_move_one(n
, m
, "key 3") == 0);
157 assert_se(hashmap_move_one(n
, m
, "key 4") == 0);
159 r
= hashmap_get(n
, "key 3");
160 assert_se(r
&& streq(r
, "val3"));
161 r
= hashmap_get(n
, "key 4");
162 assert_se(r
&& streq(r
, "val4"));
163 r
= hashmap_get(m
, "key 3");
166 assert_se(hashmap_move_one(n
, m
, "key 3") == -EEXIST
);
168 hashmap_free_free(m
);
169 hashmap_free_free(n
);
172 static void test_hashmap_move(void) {
174 char *val1
, *val2
, *val3
, *val4
, *r
;
176 log_info("/* %s */", __func__
);
178 val1
= strdup("val1");
180 val2
= strdup("val2");
182 val3
= strdup("val3");
184 val4
= strdup("val4");
187 m
= hashmap_new(&string_hash_ops
);
188 n
= hashmap_new(&string_hash_ops
);
190 hashmap_put(n
, "key 1", strdup(val1
));
191 hashmap_put(m
, "key 1", val1
);
192 hashmap_put(m
, "key 2", val2
);
193 hashmap_put(m
, "key 3", val3
);
194 hashmap_put(m
, "key 4", val4
);
196 assert_se(hashmap_move(n
, NULL
) == 0);
197 assert_se(hashmap_move(n
, m
) == 0);
199 assert_se(hashmap_size(m
) == 1);
200 r
= hashmap_get(m
, "key 1");
201 assert_se(r
&& streq(r
, "val1"));
203 r
= hashmap_get(n
, "key 1");
204 assert_se(r
&& streq(r
, "val1"));
205 r
= hashmap_get(n
, "key 2");
206 assert_se(r
&& streq(r
, "val2"));
207 r
= hashmap_get(n
, "key 3");
208 assert_se(r
&& streq(r
, "val3"));
209 r
= hashmap_get(n
, "key 4");
210 assert_se(r
&& streq(r
, "val4"));
212 hashmap_free_free(m
);
213 hashmap_free_free(n
);
216 static void test_hashmap_update(void) {
218 char *val1
, *val2
, *r
;
220 log_info("/* %s */", __func__
);
222 m
= hashmap_new(&string_hash_ops
);
223 val1
= strdup("old_value");
225 val2
= strdup("new_value");
228 hashmap_put(m
, "key 1", val1
);
229 r
= hashmap_get(m
, "key 1");
230 assert_se(streq(r
, "old_value"));
232 assert_se(hashmap_update(m
, "key 2", val2
) == -ENOENT
);
233 r
= hashmap_get(m
, "key 1");
234 assert_se(streq(r
, "old_value"));
236 assert_se(hashmap_update(m
, "key 1", val2
) == 0);
237 r
= hashmap_get(m
, "key 1");
238 assert_se(streq(r
, "new_value"));
245 static void test_hashmap_put(void) {
247 int valid_hashmap_put
;
248 void *val1
= (void*) "val 1";
249 void *val2
= (void*) "val 2";
250 _cleanup_free_
char* key1
= NULL
;
252 log_info("/* %s */", __func__
);
254 assert_se(hashmap_ensure_allocated(&m
, &string_hash_ops
) >= 0);
257 valid_hashmap_put
= hashmap_put(m
, "key 1", val1
);
258 assert_se(valid_hashmap_put
== 1);
259 assert_se(hashmap_put(m
, "key 1", val1
) == 0);
260 assert_se(hashmap_put(m
, "key 1", val2
) == -EEXIST
);
261 key1
= strdup("key 1");
262 assert_se(hashmap_put(m
, key1
, val1
) == 0);
263 assert_se(hashmap_put(m
, key1
, val2
) == -EEXIST
);
268 static void test_hashmap_remove(void) {
269 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
272 log_info("/* %s */", __func__
);
274 r
= hashmap_remove(NULL
, "key 1");
275 assert_se(r
== NULL
);
277 m
= hashmap_new(&string_hash_ops
);
280 r
= hashmap_remove(m
, "no such key");
281 assert_se(r
== NULL
);
283 hashmap_put(m
, "key 1", (void*) "val 1");
284 hashmap_put(m
, "key 2", (void*) "val 2");
286 r
= hashmap_remove(m
, "key 1");
287 assert_se(streq(r
, "val 1"));
289 r
= hashmap_get(m
, "key 2");
290 assert_se(streq(r
, "val 2"));
291 assert_se(!hashmap_get(m
, "key 1"));
294 static void test_hashmap_remove2(void) {
295 _cleanup_hashmap_free_free_free_ Hashmap
*m
= NULL
;
296 char key1
[] = "key 1";
297 char key2
[] = "key 2";
298 char val1
[] = "val 1";
299 char val2
[] = "val 2";
302 log_info("/* %s */", __func__
);
304 r
= hashmap_remove2(NULL
, "key 1", &r2
);
305 assert_se(r
== NULL
);
307 m
= hashmap_new(&string_hash_ops
);
310 r
= hashmap_remove2(m
, "no such key", &r2
);
311 assert_se(r
== NULL
);
313 hashmap_put(m
, strdup(key1
), strdup(val1
));
314 hashmap_put(m
, strdup(key2
), strdup(val2
));
316 r
= hashmap_remove2(m
, key1
, &r2
);
317 assert_se(streq(r
, val1
));
318 assert_se(streq(r2
, key1
));
322 r
= hashmap_get(m
, key2
);
323 assert_se(streq(r
, val2
));
324 assert_se(!hashmap_get(m
, key1
));
327 static void test_hashmap_remove_value(void) {
328 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
331 char val1
[] = "val 1";
332 char val2
[] = "val 2";
334 log_info("/* %s */", __func__
);
336 r
= hashmap_remove_value(NULL
, "key 1", val1
);
337 assert_se(r
== NULL
);
339 m
= hashmap_new(&string_hash_ops
);
342 r
= hashmap_remove_value(m
, "key 1", val1
);
343 assert_se(r
== NULL
);
345 hashmap_put(m
, "key 1", val1
);
346 hashmap_put(m
, "key 2", val2
);
348 r
= hashmap_remove_value(m
, "key 1", val1
);
349 assert_se(streq(r
, "val 1"));
351 r
= hashmap_get(m
, "key 2");
352 assert_se(streq(r
, "val 2"));
353 assert_se(!hashmap_get(m
, "key 1"));
355 r
= hashmap_remove_value(m
, "key 2", val1
);
356 assert_se(r
== NULL
);
358 r
= hashmap_get(m
, "key 2");
359 assert_se(streq(r
, "val 2"));
360 assert_se(!hashmap_get(m
, "key 1"));
363 static void test_hashmap_remove_and_put(void) {
364 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
368 log_info("/* %s */", __func__
);
370 m
= hashmap_new(&string_hash_ops
);
373 valid
= hashmap_remove_and_put(m
, "invalid key", "new key", NULL
);
374 assert_se(valid
== -ENOENT
);
376 valid
= hashmap_put(m
, "key 1", (void*) (const char *) "val 1");
377 assert_se(valid
== 1);
379 valid
= hashmap_remove_and_put(NULL
, "key 1", "key 2", (void*) (const char *) "val 2");
380 assert_se(valid
== -ENOENT
);
382 valid
= hashmap_remove_and_put(m
, "key 1", "key 2", (void*) (const char *) "val 2");
383 assert_se(valid
== 0);
385 r
= hashmap_get(m
, "key 2");
386 assert_se(streq(r
, "val 2"));
387 assert_se(!hashmap_get(m
, "key 1"));
389 valid
= hashmap_put(m
, "key 3", (void*) (const char *) "val 3");
390 assert_se(valid
== 1);
391 valid
= hashmap_remove_and_put(m
, "key 3", "key 2", (void*) (const char *) "val 2");
392 assert_se(valid
== -EEXIST
);
395 static void test_hashmap_remove_and_replace(void) {
396 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
398 void *key1
= UINT_TO_PTR(1);
399 void *key2
= UINT_TO_PTR(2);
400 void *key3
= UINT_TO_PTR(3);
404 log_info("/* %s */", __func__
);
406 m
= hashmap_new(&trivial_hash_ops
);
409 valid
= hashmap_remove_and_replace(m
, key1
, key2
, NULL
);
410 assert_se(valid
== -ENOENT
);
412 valid
= hashmap_put(m
, key1
, key1
);
413 assert_se(valid
== 1);
415 valid
= hashmap_remove_and_replace(NULL
, key1
, key2
, key2
);
416 assert_se(valid
== -ENOENT
);
418 valid
= hashmap_remove_and_replace(m
, key1
, key2
, key2
);
419 assert_se(valid
== 0);
421 r
= hashmap_get(m
, key2
);
422 assert_se(r
== key2
);
423 assert_se(!hashmap_get(m
, key1
));
425 valid
= hashmap_put(m
, key3
, key3
);
426 assert_se(valid
== 1);
427 valid
= hashmap_remove_and_replace(m
, key3
, key2
, key2
);
428 assert_se(valid
== 0);
429 r
= hashmap_get(m
, key2
);
430 assert_se(r
== key2
);
431 assert_se(!hashmap_get(m
, key3
));
433 /* Repeat this test several times to increase the chance of hitting
434 * the less likely case in hashmap_remove_and_replace where it
435 * compensates for the backward shift. */
436 for (i
= 0; i
< 20; i
++) {
439 for (j
= 1; j
< 7; j
++)
440 hashmap_put(m
, UINT_TO_PTR(10*i
+ j
), UINT_TO_PTR(10*i
+ j
));
441 valid
= hashmap_remove_and_replace(m
, UINT_TO_PTR(10*i
+ 1),
442 UINT_TO_PTR(10*i
+ 2),
443 UINT_TO_PTR(10*i
+ 2));
444 assert_se(valid
== 0);
445 assert_se(!hashmap_get(m
, UINT_TO_PTR(10*i
+ 1)));
446 for (j
= 2; j
< 7; j
++) {
447 r
= hashmap_get(m
, UINT_TO_PTR(10*i
+ j
));
448 assert_se(r
== UINT_TO_PTR(10*i
+ j
));
453 static void test_hashmap_ensure_allocated(void) {
457 log_info("/* %s */", __func__
);
459 m
= hashmap_new(&string_hash_ops
);
461 valid_hashmap
= hashmap_ensure_allocated(&m
, &string_hash_ops
);
462 assert_se(valid_hashmap
== 0);
468 static void test_hashmap_foreach_key(void) {
471 bool key_found
[] = { false, false, false, false };
474 static const char key_table
[] =
480 log_info("/* %s */", __func__
);
482 m
= hashmap_new(&string_hash_ops
);
484 NULSTR_FOREACH(key
, key_table
)
485 hashmap_put(m
, key
, (void*) (const char*) "my dummy val");
487 HASHMAP_FOREACH_KEY(s
, key
, m
, i
) {
489 if (!key_found
[0] && streq(key
, "key 1"))
491 else if (!key_found
[1] && streq(key
, "key 2"))
493 else if (!key_found
[2] && streq(key
, "key 3"))
495 else if (!key_found
[3] && streq(key
, "fail"))
500 assert_se(key_found
[0] && key_found
[1] && key_found
[2] && !key_found
[3]);
505 static void test_hashmap_foreach(void) {
508 bool value_found
[] = { false, false, false, false };
509 char *val1
, *val2
, *val3
, *val4
, *s
;
512 log_info("/* %s */", __func__
);
514 val1
= strdup("my val1");
516 val2
= strdup("my val2");
518 val3
= strdup("my val3");
520 val4
= strdup("my val4");
526 HASHMAP_FOREACH(s
, m
, i
)
528 assert_se(count
== 0);
530 m
= hashmap_new(&string_hash_ops
);
533 HASHMAP_FOREACH(s
, m
, i
)
535 assert_se(count
== 0);
537 hashmap_put(m
, "Key 1", val1
);
538 hashmap_put(m
, "Key 2", val2
);
539 hashmap_put(m
, "Key 3", val3
);
540 hashmap_put(m
, "Key 4", val4
);
542 HASHMAP_FOREACH(s
, m
, i
) {
543 if (!value_found
[0] && streq(s
, val1
))
544 value_found
[0] = true;
545 else if (!value_found
[1] && streq(s
, val2
))
546 value_found
[1] = true;
547 else if (!value_found
[2] && streq(s
, val3
))
548 value_found
[2] = true;
549 else if (!value_found
[3] && streq(s
, val4
))
550 value_found
[3] = true;
554 assert_se(value_found
[0] && value_found
[1] && value_found
[2] && value_found
[3]);
556 hashmap_free_free(m
);
559 static void test_hashmap_merge(void) {
562 char *val1
, *val2
, *val3
, *val4
, *r
;
564 log_info("/* %s */", __func__
);
566 val1
= strdup("my val1");
568 val2
= strdup("my val2");
570 val3
= strdup("my val3");
572 val4
= strdup("my val4");
575 n
= hashmap_new(&string_hash_ops
);
576 m
= hashmap_new(&string_hash_ops
);
578 hashmap_put(m
, "Key 1", val1
);
579 hashmap_put(m
, "Key 2", val2
);
580 hashmap_put(n
, "Key 3", val3
);
581 hashmap_put(n
, "Key 4", val4
);
583 assert_se(hashmap_merge(m
, n
) == 0);
584 r
= hashmap_get(m
, "Key 3");
585 assert_se(r
&& streq(r
, "my val3"));
586 r
= hashmap_get(m
, "Key 4");
587 assert_se(r
&& streq(r
, "my val4"));
592 hashmap_free_free(m
);
595 static void test_hashmap_contains(void) {
599 log_info("/* %s */", __func__
);
601 val1
= strdup("my val");
604 m
= hashmap_new(&string_hash_ops
);
606 assert_se(!hashmap_contains(m
, "Key 1"));
607 hashmap_put(m
, "Key 1", val1
);
608 assert_se(hashmap_contains(m
, "Key 1"));
609 assert_se(!hashmap_contains(m
, "Key 2"));
611 assert_se(!hashmap_contains(NULL
, "Key 1"));
614 hashmap_free_free(m
);
617 static void test_hashmap_isempty(void) {
621 log_info("/* %s */", __func__
);
623 val1
= strdup("my val");
626 m
= hashmap_new(&string_hash_ops
);
628 assert_se(hashmap_isempty(m
));
629 hashmap_put(m
, "Key 1", val1
);
630 assert_se(!hashmap_isempty(m
));
633 hashmap_free_free(m
);
636 static void test_hashmap_size(void) {
638 char *val1
, *val2
, *val3
, *val4
;
640 log_info("/* %s */", __func__
);
642 val1
= strdup("my val");
644 val2
= strdup("my val");
646 val3
= strdup("my val");
648 val4
= strdup("my val");
651 assert_se(hashmap_size(NULL
) == 0);
652 assert_se(hashmap_buckets(NULL
) == 0);
654 m
= hashmap_new(&string_hash_ops
);
656 hashmap_put(m
, "Key 1", val1
);
657 hashmap_put(m
, "Key 2", val2
);
658 hashmap_put(m
, "Key 3", val3
);
659 hashmap_put(m
, "Key 4", val4
);
662 assert_se(hashmap_size(m
) == 4);
663 assert_se(hashmap_buckets(m
) >= 4);
664 hashmap_free_free(m
);
667 static void test_hashmap_get(void) {
672 log_info("/* %s */", __func__
);
674 val
= strdup("my val");
677 r
= hashmap_get(NULL
, "Key 1");
678 assert_se(r
== NULL
);
680 m
= hashmap_new(&string_hash_ops
);
682 hashmap_put(m
, "Key 1", val
);
684 r
= hashmap_get(m
, "Key 1");
685 assert_se(streq(r
, val
));
687 r
= hashmap_get(m
, "no such key");
688 assert_se(r
== NULL
);
691 hashmap_free_free(m
);
694 static void test_hashmap_get2(void) {
698 char key_orig
[] = "Key 1";
701 log_info("/* %s */", __func__
);
703 val
= strdup("my val");
706 key_copy
= strdup(key_orig
);
709 r
= hashmap_get2(NULL
, key_orig
, &key_copy
);
710 assert_se(r
== NULL
);
712 m
= hashmap_new(&string_hash_ops
);
714 hashmap_put(m
, key_copy
, val
);
717 r
= hashmap_get2(m
, key_orig
, &key_copy
);
718 assert_se(streq(r
, val
));
719 assert_se(key_orig
!= key_copy
);
720 assert_se(streq(key_orig
, key_copy
));
722 r
= hashmap_get2(m
, "no such key", NULL
);
723 assert_se(r
== NULL
);
726 hashmap_free_free_free(m
);
729 static void crippled_hashmap_func(const void *p
, struct siphash
*state
) {
730 return trivial_hash_func(INT_TO_PTR(PTR_TO_INT(p
) & 0xff), state
);
733 static const struct hash_ops crippled_hashmap_ops
= {
734 .hash
= crippled_hashmap_func
,
735 .compare
= trivial_compare_func
,
738 static void test_hashmap_many(void) {
742 bool slow
= slow_tests_enabled();
745 const struct hash_ops
*ops
;
748 { "trivial_hashmap_ops", NULL
, slow
? 1 << 20 : 240 },
749 { "crippled_hashmap_ops", &crippled_hashmap_ops
, slow
? 1 << 14 : 140 },
752 log_info("/* %s (%s) */", __func__
, slow
? "slow" : "fast");
754 for (j
= 0; j
< ELEMENTSOF(tests
); j
++) {
755 usec_t ts
= now(CLOCK_MONOTONIC
), n
;
756 char b
[FORMAT_TIMESPAN_MAX
];
758 assert_se(h
= hashmap_new(tests
[j
].ops
));
760 for (i
= 1; i
< tests
[j
].n_entries
*3; i
+=3) {
761 assert_se(hashmap_put(h
, UINT_TO_PTR(i
), UINT_TO_PTR(i
)) >= 0);
762 assert_se(PTR_TO_UINT(hashmap_get(h
, UINT_TO_PTR(i
))) == i
);
765 for (i
= 1; i
< tests
[j
].n_entries
*3; i
++)
766 assert_se(hashmap_contains(h
, UINT_TO_PTR(i
)) == (i
% 3 == 1));
768 log_info("%s %u <= %u * 0.8 = %g",
769 tests
[j
].title
, hashmap_size(h
), hashmap_buckets(h
), hashmap_buckets(h
) * 0.8);
771 assert_se(hashmap_size(h
) <= hashmap_buckets(h
) * 0.8);
772 assert_se(hashmap_size(h
) == tests
[j
].n_entries
);
774 while (!hashmap_isempty(h
)) {
775 k
= hashmap_first_key(h
);
776 v
= hashmap_remove(h
, k
);
782 n
= now(CLOCK_MONOTONIC
);
783 log_info("test took %s", format_timespan(b
, sizeof b
, n
- ts
, 0));
787 extern unsigned custom_counter
;
788 extern const struct hash_ops boring_hash_ops
, custom_hash_ops
;
790 static void test_hashmap_free(void) {
792 bool slow
= slow_tests_enabled();
794 char b
[FORMAT_TIMESPAN_MAX
];
795 unsigned n_entries
= slow
? 1 << 20 : 240;
799 const struct hash_ops
*ops
;
800 unsigned expect_counter
;
802 { "string_hash_ops", &boring_hash_ops
, 2 * n_entries
},
803 { "custom_free_hash_ops", &custom_hash_ops
, 0 },
806 log_info("/* %s (%s, %u entries) */", __func__
, slow
? "slow" : "fast", n_entries
);
808 for (unsigned j
= 0; j
< ELEMENTSOF(tests
); j
++) {
809 ts
= now(CLOCK_MONOTONIC
);
810 assert_se(h
= hashmap_new(tests
[j
].ops
));
813 for (unsigned i
= 0; i
< n_entries
; i
++) {
814 char s
[DECIMAL_STR_MAX(unsigned)];
817 xsprintf(s
, "%u", i
);
818 assert_se(k
= strdup(s
));
819 assert_se(v
= strdup(s
));
822 assert_se(hashmap_put(h
, k
, v
) >= 0);
827 n
= now(CLOCK_MONOTONIC
);
828 log_info("%s test took %s", tests
[j
].title
, format_timespan(b
, sizeof b
, n
- ts
, 0));
830 assert_se(custom_counter
== tests
[j
].expect_counter
);
834 static void test_hashmap_first(void) {
835 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
837 log_info("/* %s */", __func__
);
839 m
= hashmap_new(&string_hash_ops
);
842 assert_se(!hashmap_first(m
));
843 assert_se(hashmap_put(m
, "key 1", (void*) "val 1") == 1);
844 assert_se(streq(hashmap_first(m
), "val 1"));
845 assert_se(hashmap_put(m
, "key 2", (void*) "val 2") == 1);
847 assert_se(streq(hashmap_first(m
), "val 1"));
848 assert_se(hashmap_remove(m
, "key 1"));
849 assert_se(streq(hashmap_first(m
), "val 2"));
853 static void test_hashmap_first_key(void) {
854 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
856 log_info("/* %s */", __func__
);
858 m
= hashmap_new(&string_hash_ops
);
861 assert_se(!hashmap_first_key(m
));
862 assert_se(hashmap_put(m
, "key 1", NULL
) == 1);
863 assert_se(streq(hashmap_first_key(m
), "key 1"));
864 assert_se(hashmap_put(m
, "key 2", NULL
) == 1);
866 assert_se(streq(hashmap_first_key(m
), "key 1"));
867 assert_se(hashmap_remove(m
, "key 1") == NULL
);
868 assert_se(streq(hashmap_first_key(m
), "key 2"));
872 static void test_hashmap_steal_first_key(void) {
873 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
875 log_info("/* %s */", __func__
);
877 m
= hashmap_new(&string_hash_ops
);
880 assert_se(!hashmap_steal_first_key(m
));
881 assert_se(hashmap_put(m
, "key 1", NULL
) == 1);
882 assert_se(streq(hashmap_steal_first_key(m
), "key 1"));
884 assert_se(hashmap_isempty(m
));
887 static void test_hashmap_steal_first(void) {
888 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
892 log_info("/* %s */", __func__
);
894 m
= hashmap_new(&string_hash_ops
);
897 assert_se(hashmap_put(m
, "key 1", (void*) "1") == 1);
898 assert_se(hashmap_put(m
, "key 2", (void*) "22") == 1);
899 assert_se(hashmap_put(m
, "key 3", (void*) "333") == 1);
901 while ((val
= hashmap_steal_first(m
)))
902 seen
[strlen(val
) - 1]++;
904 assert_se(seen
[0] == 1 && seen
[1] == 1 && seen
[2] == 1);
906 assert_se(hashmap_isempty(m
));
909 static void test_hashmap_clear_free_free(void) {
910 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
912 log_info("/* %s */", __func__
);
914 m
= hashmap_new(&string_hash_ops
);
917 assert_se(hashmap_put(m
, strdup("key 1"), NULL
) == 1);
918 assert_se(hashmap_put(m
, strdup("key 2"), NULL
) == 1);
919 assert_se(hashmap_put(m
, strdup("key 3"), NULL
) == 1);
921 hashmap_clear_free_free(m
);
922 assert_se(hashmap_isempty(m
));
924 assert_se(hashmap_put(m
, strdup("key 1"), strdup("value 1")) == 1);
925 assert_se(hashmap_put(m
, strdup("key 2"), strdup("value 2")) == 1);
926 assert_se(hashmap_put(m
, strdup("key 3"), strdup("value 3")) == 1);
928 hashmap_clear_free_free(m
);
929 assert_se(hashmap_isempty(m
));
932 DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(test_hash_ops_key
, char, string_hash_func
, string_compare_func
, free
);
933 DEFINE_PRIVATE_HASH_OPS_FULL(test_hash_ops_full
, char, string_hash_func
, string_compare_func
, free
, char, free
);
935 static void test_hashmap_clear_free_with_destructor(void) {
936 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
938 log_info("/* %s */", __func__
);
940 m
= hashmap_new(&test_hash_ops_key
);
943 assert_se(hashmap_put(m
, strdup("key 1"), NULL
) == 1);
944 assert_se(hashmap_put(m
, strdup("key 2"), NULL
) == 1);
945 assert_se(hashmap_put(m
, strdup("key 3"), NULL
) == 1);
947 hashmap_clear_free(m
);
948 assert_se(hashmap_isempty(m
));
951 m
= hashmap_new(&test_hash_ops_full
);
954 assert_se(hashmap_put(m
, strdup("key 1"), strdup("value 1")) == 1);
955 assert_se(hashmap_put(m
, strdup("key 2"), strdup("value 2")) == 1);
956 assert_se(hashmap_put(m
, strdup("key 3"), strdup("value 3")) == 1);
958 hashmap_clear_free(m
);
959 assert_se(hashmap_isempty(m
));
962 static void test_hashmap_reserve(void) {
963 _cleanup_hashmap_free_ Hashmap
*m
= NULL
;
965 log_info("/* %s */", __func__
);
967 m
= hashmap_new(&string_hash_ops
);
969 assert_se(hashmap_reserve(m
, 1) == 0);
970 assert_se(hashmap_buckets(m
) < 1000);
971 assert_se(hashmap_reserve(m
, 1000) == 0);
972 assert_se(hashmap_buckets(m
) >= 1000);
973 assert_se(hashmap_isempty(m
));
975 assert_se(hashmap_put(m
, "key 1", (void*) "val 1") == 1);
977 assert_se(hashmap_reserve(m
, UINT_MAX
) == -ENOMEM
);
978 assert_se(hashmap_reserve(m
, UINT_MAX
- 1) == -ENOMEM
);
981 void test_hashmap_funcs(void) {
982 log_parse_environment();
986 test_hashmap_get_strv();
987 test_hashmap_move_one();
989 test_hashmap_replace();
990 test_hashmap_update();
992 test_hashmap_remove();
993 test_hashmap_remove2();
994 test_hashmap_remove_value();
995 test_hashmap_remove_and_put();
996 test_hashmap_remove_and_replace();
997 test_hashmap_ensure_allocated();
998 test_hashmap_foreach();
999 test_hashmap_foreach_key();
1000 test_hashmap_contains();
1001 test_hashmap_merge();
1002 test_hashmap_isempty();
1004 test_hashmap_get2();
1005 test_hashmap_size();
1006 test_hashmap_many();
1007 test_hashmap_free();
1008 test_hashmap_first();
1009 test_hashmap_first_key();
1010 test_hashmap_steal_first_key();
1011 test_hashmap_steal_first();
1012 test_hashmap_clear_free_free();
1013 test_hashmap_clear_free_with_destructor();
1014 test_hashmap_reserve();