]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-hashmap-plain.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / test / test-hashmap-plain.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd
4
5 Copyright 2013 Daniel Buch
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include "alloc-util.h"
22 #include "env-util.h"
23 #include "hashmap.h"
24 #include "log.h"
25 #include "string-util.h"
26 #include "strv.h"
27 #include "util.h"
28
29 static bool arg_slow = false;
30
31 void test_hashmap_funcs(void);
32
33 static void test_hashmap_replace(void) {
34 Hashmap *m;
35 char *val1, *val2, *val3, *val4, *val5, *r;
36
37 log_info("%s", __func__);
38
39 m = hashmap_new(&string_hash_ops);
40
41 val1 = strdup("val1");
42 assert_se(val1);
43 val2 = strdup("val2");
44 assert_se(val2);
45 val3 = strdup("val3");
46 assert_se(val3);
47 val4 = strdup("val4");
48 assert_se(val4);
49 val5 = strdup("val5");
50 assert_se(val5);
51
52 hashmap_put(m, "key 1", val1);
53 hashmap_put(m, "key 2", val2);
54 hashmap_put(m, "key 3", val3);
55 hashmap_put(m, "key 4", val4);
56
57 hashmap_replace(m, "key 3", val1);
58 r = hashmap_get(m, "key 3");
59 assert_se(streq(r, "val1"));
60
61 hashmap_replace(m, "key 5", val5);
62 r = hashmap_get(m, "key 5");
63 assert_se(streq(r, "val5"));
64
65 free(val1);
66 free(val2);
67 free(val3);
68 free(val4);
69 free(val5);
70 hashmap_free(m);
71 }
72
73 static void test_hashmap_copy(void) {
74 Hashmap *m, *copy;
75 char *val1, *val2, *val3, *val4, *r;
76
77 log_info("%s", __func__);
78
79 val1 = strdup("val1");
80 assert_se(val1);
81 val2 = strdup("val2");
82 assert_se(val2);
83 val3 = strdup("val3");
84 assert_se(val3);
85 val4 = strdup("val4");
86 assert_se(val4);
87
88 m = hashmap_new(&string_hash_ops);
89
90 hashmap_put(m, "key 1", val1);
91 hashmap_put(m, "key 2", val2);
92 hashmap_put(m, "key 3", val3);
93 hashmap_put(m, "key 4", val4);
94
95 copy = hashmap_copy(m);
96
97 r = hashmap_get(copy, "key 1");
98 assert_se(streq(r, "val1"));
99 r = hashmap_get(copy, "key 2");
100 assert_se(streq(r, "val2"));
101 r = hashmap_get(copy, "key 3");
102 assert_se(streq(r, "val3"));
103 r = hashmap_get(copy, "key 4");
104 assert_se(streq(r, "val4"));
105
106 hashmap_free_free(copy);
107 hashmap_free(m);
108 }
109
110 static void test_hashmap_get_strv(void) {
111 Hashmap *m;
112 char **strv;
113 char *val1, *val2, *val3, *val4;
114
115 log_info("%s", __func__);
116
117 val1 = strdup("val1");
118 assert_se(val1);
119 val2 = strdup("val2");
120 assert_se(val2);
121 val3 = strdup("val3");
122 assert_se(val3);
123 val4 = strdup("val4");
124 assert_se(val4);
125
126 m = hashmap_new(&string_hash_ops);
127
128 hashmap_put(m, "key 1", val1);
129 hashmap_put(m, "key 2", val2);
130 hashmap_put(m, "key 3", val3);
131 hashmap_put(m, "key 4", val4);
132
133 strv = hashmap_get_strv(m);
134
135 #ifndef ORDERED
136 strv = strv_sort(strv);
137 #endif
138
139 assert_se(streq(strv[0], "val1"));
140 assert_se(streq(strv[1], "val2"));
141 assert_se(streq(strv[2], "val3"));
142 assert_se(streq(strv[3], "val4"));
143
144 strv_free(strv);
145
146 hashmap_free(m);
147 }
148
149 static void test_hashmap_move_one(void) {
150 Hashmap *m, *n;
151 char *val1, *val2, *val3, *val4, *r;
152
153 log_info("%s", __func__);
154
155 val1 = strdup("val1");
156 assert_se(val1);
157 val2 = strdup("val2");
158 assert_se(val2);
159 val3 = strdup("val3");
160 assert_se(val3);
161 val4 = strdup("val4");
162 assert_se(val4);
163
164 m = hashmap_new(&string_hash_ops);
165 n = hashmap_new(&string_hash_ops);
166
167 hashmap_put(m, "key 1", val1);
168 hashmap_put(m, "key 2", val2);
169 hashmap_put(m, "key 3", val3);
170 hashmap_put(m, "key 4", val4);
171
172 assert_se(hashmap_move_one(n, NULL, "key 3") == -ENOENT);
173 assert_se(hashmap_move_one(n, m, "key 5") == -ENOENT);
174 assert_se(hashmap_move_one(n, m, "key 3") == 0);
175 assert_se(hashmap_move_one(n, m, "key 4") == 0);
176
177 r = hashmap_get(n, "key 3");
178 assert_se(r && streq(r, "val3"));
179 r = hashmap_get(n, "key 4");
180 assert_se(r && streq(r, "val4"));
181 r = hashmap_get(m, "key 3");
182 assert_se(!r);
183
184 assert_se(hashmap_move_one(n, m, "key 3") == -EEXIST);
185
186 hashmap_free_free(m);
187 hashmap_free_free(n);
188 }
189
190 static void test_hashmap_move(void) {
191 Hashmap *m, *n;
192 char *val1, *val2, *val3, *val4, *r;
193
194 log_info("%s", __func__);
195
196 val1 = strdup("val1");
197 assert_se(val1);
198 val2 = strdup("val2");
199 assert_se(val2);
200 val3 = strdup("val3");
201 assert_se(val3);
202 val4 = strdup("val4");
203 assert_se(val4);
204
205 m = hashmap_new(&string_hash_ops);
206 n = hashmap_new(&string_hash_ops);
207
208 hashmap_put(n, "key 1", strdup(val1));
209 hashmap_put(m, "key 1", val1);
210 hashmap_put(m, "key 2", val2);
211 hashmap_put(m, "key 3", val3);
212 hashmap_put(m, "key 4", val4);
213
214 assert_se(hashmap_move(n, NULL) == 0);
215 assert_se(hashmap_move(n, m) == 0);
216
217 assert_se(hashmap_size(m) == 1);
218 r = hashmap_get(m, "key 1");
219 assert_se(r && streq(r, "val1"));
220
221 r = hashmap_get(n, "key 1");
222 assert_se(r && streq(r, "val1"));
223 r = hashmap_get(n, "key 2");
224 assert_se(r && streq(r, "val2"));
225 r = hashmap_get(n, "key 3");
226 assert_se(r && streq(r, "val3"));
227 r = hashmap_get(n, "key 4");
228 assert_se(r && streq(r, "val4"));
229
230 hashmap_free_free(m);
231 hashmap_free_free(n);
232 }
233
234 static void test_hashmap_update(void) {
235 Hashmap *m;
236 char *val1, *val2, *r;
237
238 log_info("%s", __func__);
239
240 m = hashmap_new(&string_hash_ops);
241 val1 = strdup("old_value");
242 assert_se(val1);
243 val2 = strdup("new_value");
244 assert_se(val2);
245
246 hashmap_put(m, "key 1", val1);
247 r = hashmap_get(m, "key 1");
248 assert_se(streq(r, "old_value"));
249
250 assert_se(hashmap_update(m, "key 2", val2) == -ENOENT);
251 r = hashmap_get(m, "key 1");
252 assert_se(streq(r, "old_value"));
253
254 assert_se(hashmap_update(m, "key 1", val2) == 0);
255 r = hashmap_get(m, "key 1");
256 assert_se(streq(r, "new_value"));
257
258 free(val1);
259 free(val2);
260 hashmap_free(m);
261 }
262
263 static void test_hashmap_put(void) {
264 Hashmap *m = NULL;
265 int valid_hashmap_put;
266 void *val1 = (void*) "val 1";
267 void *val2 = (void*) "val 2";
268 _cleanup_free_ char* key1 = NULL;
269
270 log_info("%s", __func__);
271
272 assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0);
273 assert_se(m);
274
275 valid_hashmap_put = hashmap_put(m, "key 1", val1);
276 assert_se(valid_hashmap_put == 1);
277 assert_se(hashmap_put(m, "key 1", val1) == 0);
278 assert_se(hashmap_put(m, "key 1", val2) == -EEXIST);
279 key1 = strdup("key 1");
280 assert_se(hashmap_put(m, key1, val1) == 0);
281 assert_se(hashmap_put(m, key1, val2) == -EEXIST);
282
283 hashmap_free(m);
284 }
285
286 static void test_hashmap_remove(void) {
287 _cleanup_hashmap_free_ Hashmap *m = NULL;
288 char *r;
289
290 log_info("%s", __func__);
291
292 r = hashmap_remove(NULL, "key 1");
293 assert_se(r == NULL);
294
295 m = hashmap_new(&string_hash_ops);
296 assert_se(m);
297
298 r = hashmap_remove(m, "no such key");
299 assert_se(r == NULL);
300
301 hashmap_put(m, "key 1", (void*) "val 1");
302 hashmap_put(m, "key 2", (void*) "val 2");
303
304 r = hashmap_remove(m, "key 1");
305 assert_se(streq(r, "val 1"));
306
307 r = hashmap_get(m, "key 2");
308 assert_se(streq(r, "val 2"));
309 assert_se(!hashmap_get(m, "key 1"));
310 }
311
312 static void test_hashmap_remove2(void) {
313 _cleanup_hashmap_free_free_free_ Hashmap *m = NULL;
314 char key1[] = "key 1";
315 char key2[] = "key 2";
316 char val1[] = "val 1";
317 char val2[] = "val 2";
318 void *r, *r2;
319
320 log_info("%s", __func__);
321
322 r = hashmap_remove2(NULL, "key 1", &r2);
323 assert_se(r == NULL);
324
325 m = hashmap_new(&string_hash_ops);
326 assert_se(m);
327
328 r = hashmap_remove2(m, "no such key", &r2);
329 assert_se(r == NULL);
330
331 hashmap_put(m, strdup(key1), strdup(val1));
332 hashmap_put(m, strdup(key2), strdup(val2));
333
334 r = hashmap_remove2(m, key1, &r2);
335 assert_se(streq(r, val1));
336 assert_se(streq(r2, key1));
337 free(r);
338 free(r2);
339
340 r = hashmap_get(m, key2);
341 assert_se(streq(r, val2));
342 assert_se(!hashmap_get(m, key1));
343 }
344
345 static void test_hashmap_remove_value(void) {
346 _cleanup_hashmap_free_ Hashmap *m = NULL;
347 char *r;
348
349 char val1[] = "val 1";
350 char val2[] = "val 2";
351
352 log_info("%s", __func__);
353
354 r = hashmap_remove_value(NULL, "key 1", val1);
355 assert_se(r == NULL);
356
357 m = hashmap_new(&string_hash_ops);
358 assert_se(m);
359
360 r = hashmap_remove_value(m, "key 1", val1);
361 assert_se(r == NULL);
362
363 hashmap_put(m, "key 1", val1);
364 hashmap_put(m, "key 2", val2);
365
366 r = hashmap_remove_value(m, "key 1", val1);
367 assert_se(streq(r, "val 1"));
368
369 r = hashmap_get(m, "key 2");
370 assert_se(streq(r, "val 2"));
371 assert_se(!hashmap_get(m, "key 1"));
372
373 r = hashmap_remove_value(m, "key 2", val1);
374 assert_se(r == NULL);
375
376 r = hashmap_get(m, "key 2");
377 assert_se(streq(r, "val 2"));
378 assert_se(!hashmap_get(m, "key 1"));
379 }
380
381 static void test_hashmap_remove_and_put(void) {
382 _cleanup_hashmap_free_ Hashmap *m = NULL;
383 int valid;
384 char *r;
385
386 log_info("%s", __func__);
387
388 m = hashmap_new(&string_hash_ops);
389 assert_se(m);
390
391 valid = hashmap_remove_and_put(m, "invalid key", "new key", NULL);
392 assert_se(valid == -ENOENT);
393
394 valid = hashmap_put(m, "key 1", (void*) (const char *) "val 1");
395 assert_se(valid == 1);
396
397 valid = hashmap_remove_and_put(NULL, "key 1", "key 2", (void*) (const char *) "val 2");
398 assert_se(valid == -ENOENT);
399
400 valid = hashmap_remove_and_put(m, "key 1", "key 2", (void*) (const char *) "val 2");
401 assert_se(valid == 0);
402
403 r = hashmap_get(m, "key 2");
404 assert_se(streq(r, "val 2"));
405 assert_se(!hashmap_get(m, "key 1"));
406
407 valid = hashmap_put(m, "key 3", (void*) (const char *) "val 3");
408 assert_se(valid == 1);
409 valid = hashmap_remove_and_put(m, "key 3", "key 2", (void*) (const char *) "val 2");
410 assert_se(valid == -EEXIST);
411 }
412
413 static void test_hashmap_remove_and_replace(void) {
414 _cleanup_hashmap_free_ Hashmap *m = NULL;
415 int valid;
416 void *key1 = UINT_TO_PTR(1);
417 void *key2 = UINT_TO_PTR(2);
418 void *key3 = UINT_TO_PTR(3);
419 void *r;
420 int i, j;
421
422 log_info("%s", __func__);
423
424 m = hashmap_new(&trivial_hash_ops);
425 assert_se(m);
426
427 valid = hashmap_remove_and_replace(m, key1, key2, NULL);
428 assert_se(valid == -ENOENT);
429
430 valid = hashmap_put(m, key1, key1);
431 assert_se(valid == 1);
432
433 valid = hashmap_remove_and_replace(NULL, key1, key2, key2);
434 assert_se(valid == -ENOENT);
435
436 valid = hashmap_remove_and_replace(m, key1, key2, key2);
437 assert_se(valid == 0);
438
439 r = hashmap_get(m, key2);
440 assert_se(r == key2);
441 assert_se(!hashmap_get(m, key1));
442
443 valid = hashmap_put(m, key3, key3);
444 assert_se(valid == 1);
445 valid = hashmap_remove_and_replace(m, key3, key2, key2);
446 assert_se(valid == 0);
447 r = hashmap_get(m, key2);
448 assert_se(r == key2);
449 assert_se(!hashmap_get(m, key3));
450
451 /* Repeat this test several times to increase the chance of hitting
452 * the less likely case in hashmap_remove_and_replace where it
453 * compensates for the backward shift. */
454 for (i = 0; i < 20; i++) {
455 hashmap_clear(m);
456
457 for (j = 1; j < 7; j++)
458 hashmap_put(m, UINT_TO_PTR(10*i + j), UINT_TO_PTR(10*i + j));
459 valid = hashmap_remove_and_replace(m, UINT_TO_PTR(10*i + 1),
460 UINT_TO_PTR(10*i + 2),
461 UINT_TO_PTR(10*i + 2));
462 assert_se(valid == 0);
463 assert_se(!hashmap_get(m, UINT_TO_PTR(10*i + 1)));
464 for (j = 2; j < 7; j++) {
465 r = hashmap_get(m, UINT_TO_PTR(10*i + j));
466 assert_se(r == UINT_TO_PTR(10*i + j));
467 }
468 }
469 }
470
471 static void test_hashmap_ensure_allocated(void) {
472 Hashmap *m;
473 int valid_hashmap;
474
475 log_info("%s", __func__);
476
477 m = hashmap_new(&string_hash_ops);
478
479 valid_hashmap = hashmap_ensure_allocated(&m, &string_hash_ops);
480 assert_se(valid_hashmap == 0);
481
482 assert_se(m);
483 hashmap_free(m);
484 }
485
486 static void test_hashmap_foreach_key(void) {
487 Hashmap *m;
488 Iterator i;
489 bool key_found[] = { false, false, false, false };
490 const char *s;
491 const char *key;
492 static const char key_table[] =
493 "key 1\0"
494 "key 2\0"
495 "key 3\0"
496 "key 4\0";
497
498 log_info("%s", __func__);
499
500 m = hashmap_new(&string_hash_ops);
501
502 NULSTR_FOREACH(key, key_table)
503 hashmap_put(m, key, (void*) (const char*) "my dummy val");
504
505 HASHMAP_FOREACH_KEY(s, key, m, i) {
506 assert(s);
507 if (!key_found[0] && streq(key, "key 1"))
508 key_found[0] = true;
509 else if (!key_found[1] && streq(key, "key 2"))
510 key_found[1] = true;
511 else if (!key_found[2] && streq(key, "key 3"))
512 key_found[2] = true;
513 else if (!key_found[3] && streq(key, "fail"))
514 key_found[3] = true;
515 }
516
517 assert_se(m);
518 assert_se(key_found[0] && key_found[1] && key_found[2] && !key_found[3]);
519
520 hashmap_free(m);
521 }
522
523 static void test_hashmap_foreach(void) {
524 Hashmap *m;
525 Iterator i;
526 bool value_found[] = { false, false, false, false };
527 char *val1, *val2, *val3, *val4, *s;
528 unsigned count;
529
530 log_info("%s", __func__);
531
532 val1 = strdup("my val1");
533 assert_se(val1);
534 val2 = strdup("my val2");
535 assert_se(val2);
536 val3 = strdup("my val3");
537 assert_se(val3);
538 val4 = strdup("my val4");
539 assert_se(val4);
540
541 m = NULL;
542
543 count = 0;
544 HASHMAP_FOREACH(s, m, i)
545 count++;
546 assert_se(count == 0);
547
548 m = hashmap_new(&string_hash_ops);
549
550 count = 0;
551 HASHMAP_FOREACH(s, m, i)
552 count++;
553 assert_se(count == 0);
554
555 hashmap_put(m, "Key 1", val1);
556 hashmap_put(m, "Key 2", val2);
557 hashmap_put(m, "Key 3", val3);
558 hashmap_put(m, "Key 4", val4);
559
560 HASHMAP_FOREACH(s, m, i) {
561 if (!value_found[0] && streq(s, val1))
562 value_found[0] = true;
563 else if (!value_found[1] && streq(s, val2))
564 value_found[1] = true;
565 else if (!value_found[2] && streq(s, val3))
566 value_found[2] = true;
567 else if (!value_found[3] && streq(s, val4))
568 value_found[3] = true;
569 }
570
571 assert_se(m);
572 assert_se(value_found[0] && value_found[1] && value_found[2] && value_found[3]);
573
574 hashmap_free_free(m);
575 }
576
577 static void test_hashmap_merge(void) {
578 Hashmap *m;
579 Hashmap *n;
580 char *val1, *val2, *val3, *val4, *r;
581
582 log_info("%s", __func__);
583
584 val1 = strdup("my val1");
585 assert_se(val1);
586 val2 = strdup("my val2");
587 assert_se(val2);
588 val3 = strdup("my val3");
589 assert_se(val3);
590 val4 = strdup("my val4");
591 assert_se(val4);
592
593 n = hashmap_new(&string_hash_ops);
594 m = hashmap_new(&string_hash_ops);
595
596 hashmap_put(m, "Key 1", val1);
597 hashmap_put(m, "Key 2", val2);
598 hashmap_put(n, "Key 3", val3);
599 hashmap_put(n, "Key 4", val4);
600
601 assert_se(hashmap_merge(m, n) == 0);
602 r = hashmap_get(m, "Key 3");
603 assert_se(r && streq(r, "my val3"));
604 r = hashmap_get(m, "Key 4");
605 assert_se(r && streq(r, "my val4"));
606
607 assert_se(n);
608 assert_se(m);
609 hashmap_free(n);
610 hashmap_free_free(m);
611 }
612
613 static void test_hashmap_contains(void) {
614 Hashmap *m;
615 char *val1;
616
617 log_info("%s", __func__);
618
619 val1 = strdup("my val");
620 assert_se(val1);
621
622 m = hashmap_new(&string_hash_ops);
623
624 assert_se(!hashmap_contains(m, "Key 1"));
625 hashmap_put(m, "Key 1", val1);
626 assert_se(hashmap_contains(m, "Key 1"));
627 assert_se(!hashmap_contains(m, "Key 2"));
628
629 assert_se(!hashmap_contains(NULL, "Key 1"));
630
631 assert_se(m);
632 hashmap_free_free(m);
633 }
634
635 static void test_hashmap_isempty(void) {
636 Hashmap *m;
637 char *val1;
638
639 log_info("%s", __func__);
640
641 val1 = strdup("my val");
642 assert_se(val1);
643
644 m = hashmap_new(&string_hash_ops);
645
646 assert_se(hashmap_isempty(m));
647 hashmap_put(m, "Key 1", val1);
648 assert_se(!hashmap_isempty(m));
649
650 assert_se(m);
651 hashmap_free_free(m);
652 }
653
654 static void test_hashmap_size(void) {
655 Hashmap *m;
656 char *val1, *val2, *val3, *val4;
657
658 log_info("%s", __func__);
659
660 val1 = strdup("my val");
661 assert_se(val1);
662 val2 = strdup("my val");
663 assert_se(val2);
664 val3 = strdup("my val");
665 assert_se(val3);
666 val4 = strdup("my val");
667 assert_se(val4);
668
669 assert_se(hashmap_size(NULL) == 0);
670 assert_se(hashmap_buckets(NULL) == 0);
671
672 m = hashmap_new(&string_hash_ops);
673
674 hashmap_put(m, "Key 1", val1);
675 hashmap_put(m, "Key 2", val2);
676 hashmap_put(m, "Key 3", val3);
677 hashmap_put(m, "Key 4", val4);
678
679 assert_se(m);
680 assert_se(hashmap_size(m) == 4);
681 assert_se(hashmap_buckets(m) >= 4);
682 hashmap_free_free(m);
683 }
684
685 static void test_hashmap_get(void) {
686 Hashmap *m;
687 char *r;
688 char *val;
689
690 log_info("%s", __func__);
691
692 val = strdup("my val");
693 assert_se(val);
694
695 r = hashmap_get(NULL, "Key 1");
696 assert_se(r == NULL);
697
698 m = hashmap_new(&string_hash_ops);
699
700 hashmap_put(m, "Key 1", val);
701
702 r = hashmap_get(m, "Key 1");
703 assert_se(streq(r, val));
704
705 r = hashmap_get(m, "no such key");
706 assert_se(r == NULL);
707
708 assert_se(m);
709 hashmap_free_free(m);
710 }
711
712 static void test_hashmap_get2(void) {
713 Hashmap *m;
714 char *r;
715 char *val;
716 char key_orig[] = "Key 1";
717 void *key_copy;
718
719 log_info("%s", __func__);
720
721 val = strdup("my val");
722 assert_se(val);
723
724 key_copy = strdup(key_orig);
725 assert_se(key_copy);
726
727 r = hashmap_get2(NULL, key_orig, &key_copy);
728 assert_se(r == NULL);
729
730 m = hashmap_new(&string_hash_ops);
731
732 hashmap_put(m, key_copy, val);
733 key_copy = NULL;
734
735 r = hashmap_get2(m, key_orig, &key_copy);
736 assert_se(streq(r, val));
737 assert_se(key_orig != key_copy);
738 assert_se(streq(key_orig, key_copy));
739
740 r = hashmap_get2(m, "no such key", NULL);
741 assert_se(r == NULL);
742
743 assert_se(m);
744 hashmap_free_free_free(m);
745 }
746
747 static void crippled_hashmap_func(const void *p, struct siphash *state) {
748 return trivial_hash_func(INT_TO_PTR(PTR_TO_INT(p) & 0xff), state);
749 }
750
751 static const struct hash_ops crippled_hashmap_ops = {
752 .hash = crippled_hashmap_func,
753 .compare = trivial_compare_func,
754 };
755
756 static void test_hashmap_many(void) {
757 Hashmap *h;
758 unsigned i, j;
759 void *v, *k;
760 const struct {
761 const struct hash_ops *ops;
762 unsigned n_entries;
763 } tests[] = {
764 { .ops = NULL, .n_entries = arg_slow ? 1 << 20 : 240 },
765 { .ops = &crippled_hashmap_ops, .n_entries = arg_slow ? 1 << 14 : 140 },
766 };
767
768 log_info("%s (%s)", __func__, arg_slow ? "slow" : "fast");
769
770 for (j = 0; j < ELEMENTSOF(tests); j++) {
771 assert_se(h = hashmap_new(tests[j].ops));
772
773 for (i = 1; i < tests[j].n_entries*3; i+=3) {
774 assert_se(hashmap_put(h, UINT_TO_PTR(i), UINT_TO_PTR(i)) >= 0);
775 assert_se(PTR_TO_UINT(hashmap_get(h, UINT_TO_PTR(i))) == i);
776 }
777
778 for (i = 1; i < tests[j].n_entries*3; i++)
779 assert_se(hashmap_contains(h, UINT_TO_PTR(i)) == (i % 3 == 1));
780
781 log_info("%u <= %u * 0.8 = %g", hashmap_size(h), hashmap_buckets(h), hashmap_buckets(h) * 0.8);
782
783 assert_se(hashmap_size(h) <= hashmap_buckets(h) * 0.8);
784 assert_se(hashmap_size(h) == tests[j].n_entries);
785
786 while (!hashmap_isempty(h)) {
787 k = hashmap_first_key(h);
788 v = hashmap_remove(h, k);
789 assert_se(v == k);
790 }
791
792 hashmap_free(h);
793 }
794 }
795
796 static void test_hashmap_first(void) {
797 _cleanup_hashmap_free_ Hashmap *m = NULL;
798
799 log_info("%s", __func__);
800
801 m = hashmap_new(&string_hash_ops);
802 assert_se(m);
803
804 assert_se(!hashmap_first(m));
805 assert_se(hashmap_put(m, "key 1", (void*) "val 1") == 1);
806 assert_se(streq(hashmap_first(m), "val 1"));
807 assert_se(hashmap_put(m, "key 2", (void*) "val 2") == 1);
808 #ifdef ORDERED
809 assert_se(streq(hashmap_first(m), "val 1"));
810 assert_se(hashmap_remove(m, "key 1"));
811 assert_se(streq(hashmap_first(m), "val 2"));
812 #endif
813 }
814
815 static void test_hashmap_first_key(void) {
816 _cleanup_hashmap_free_ Hashmap *m = NULL;
817
818 log_info("%s", __func__);
819
820 m = hashmap_new(&string_hash_ops);
821 assert_se(m);
822
823 assert_se(!hashmap_first_key(m));
824 assert_se(hashmap_put(m, "key 1", NULL) == 1);
825 assert_se(streq(hashmap_first_key(m), "key 1"));
826 assert_se(hashmap_put(m, "key 2", NULL) == 1);
827 #ifdef ORDERED
828 assert_se(streq(hashmap_first_key(m), "key 1"));
829 assert_se(hashmap_remove(m, "key 1") == NULL);
830 assert_se(streq(hashmap_first_key(m), "key 2"));
831 #endif
832 }
833
834 static void test_hashmap_steal_first_key(void) {
835 _cleanup_hashmap_free_ Hashmap *m = NULL;
836
837 log_info("%s", __func__);
838
839 m = hashmap_new(&string_hash_ops);
840 assert_se(m);
841
842 assert_se(!hashmap_steal_first_key(m));
843 assert_se(hashmap_put(m, "key 1", NULL) == 1);
844 assert_se(streq(hashmap_steal_first_key(m), "key 1"));
845
846 assert_se(hashmap_isempty(m));
847 }
848
849 static void test_hashmap_steal_first(void) {
850 _cleanup_hashmap_free_ Hashmap *m = NULL;
851 int seen[3] = {};
852 char *val;
853
854 log_info("%s", __func__);
855
856 m = hashmap_new(&string_hash_ops);
857 assert_se(m);
858
859 assert_se(hashmap_put(m, "key 1", (void*) "1") == 1);
860 assert_se(hashmap_put(m, "key 2", (void*) "22") == 1);
861 assert_se(hashmap_put(m, "key 3", (void*) "333") == 1);
862
863 while ((val = hashmap_steal_first(m)))
864 seen[strlen(val) - 1]++;
865
866 assert_se(seen[0] == 1 && seen[1] == 1 && seen[2] == 1);
867
868 assert_se(hashmap_isempty(m));
869 }
870
871 static void test_hashmap_clear_free_free(void) {
872 _cleanup_hashmap_free_ Hashmap *m = NULL;
873
874 log_info("%s", __func__);
875
876 m = hashmap_new(&string_hash_ops);
877 assert_se(m);
878
879 assert_se(hashmap_put(m, strdup("key 1"), NULL) == 1);
880 assert_se(hashmap_put(m, strdup("key 2"), NULL) == 1);
881 assert_se(hashmap_put(m, strdup("key 3"), NULL) == 1);
882
883 hashmap_clear_free_free(m);
884 assert_se(hashmap_isempty(m));
885 }
886
887 static void test_hashmap_reserve(void) {
888 _cleanup_hashmap_free_ Hashmap *m = NULL;
889
890 log_info("%s", __func__);
891
892 m = hashmap_new(&string_hash_ops);
893
894 assert_se(hashmap_reserve(m, 1) == 0);
895 assert_se(hashmap_buckets(m) < 1000);
896 assert_se(hashmap_reserve(m, 1000) == 0);
897 assert_se(hashmap_buckets(m) >= 1000);
898 assert_se(hashmap_isempty(m));
899
900 assert_se(hashmap_put(m, "key 1", (void*) "val 1") == 1);
901
902 assert_se(hashmap_reserve(m, UINT_MAX) == -ENOMEM);
903 assert_se(hashmap_reserve(m, UINT_MAX - 1) == -ENOMEM);
904 }
905
906 void test_hashmap_funcs(void) {
907 int r;
908
909 log_parse_environment();
910 log_open();
911
912 r = getenv_bool("SYSTEMD_SLOW_TESTS");
913 arg_slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT;
914
915 test_hashmap_copy();
916 test_hashmap_get_strv();
917 test_hashmap_move_one();
918 test_hashmap_move();
919 test_hashmap_replace();
920 test_hashmap_update();
921 test_hashmap_put();
922 test_hashmap_remove();
923 test_hashmap_remove2();
924 test_hashmap_remove_value();
925 test_hashmap_remove_and_put();
926 test_hashmap_remove_and_replace();
927 test_hashmap_ensure_allocated();
928 test_hashmap_foreach();
929 test_hashmap_foreach_key();
930 test_hashmap_contains();
931 test_hashmap_merge();
932 test_hashmap_isempty();
933 test_hashmap_get();
934 test_hashmap_get2();
935 test_hashmap_size();
936 test_hashmap_many();
937 test_hashmap_first();
938 test_hashmap_first_key();
939 test_hashmap_steal_first_key();
940 test_hashmap_steal_first();
941 test_hashmap_clear_free_free();
942 test_hashmap_reserve();
943 }